org.openpythia.plugin.worststatements.DeltaSnapshotWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.openpythia.plugin.worststatements.DeltaSnapshotWriter.java

Source

/**
 * Copyright 2012 msg systems ag
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
package org.openpythia.plugin.worststatements;

import org.apache.poi.ss.usermodel.*;
import org.openpythia.progress.ProgressListener;
import org.openpythia.utilities.SSUtilities;
import org.openpythia.utilities.deltasql.DeltaSQLStatementSnapshot;
import org.openpythia.utilities.deltasql.DeltaSnapshot;
import org.openpythia.utilities.sql.ExecutionPlan;
import org.openpythia.utilities.sql.ExecutionPlanStep;
import org.openpythia.utilities.sql.SQLHelper;
import org.openpythia.utilities.waitevent.WaitEventForStatementTuple;
import org.openpythia.utilities.waitevent.WaitEventForTimeSpanTuple;

import javax.swing.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class DeltaSnapshotWriter {

    private static final int INDEX_ROW_TEMPLATE_DELTA_SQL_STATEMENT = 3;
    private static final int INDEX_ROW_START_SQL_STATEMENTS = 4;
    private static final int INDEX_ROW_SUM_FORMULAS = 2;

    private static final int INDEX_COLUMN_SQL_ID = 25;
    private static final int INDEX_COLUMN_DELTA_ROWS_PROCESSED = 23;
    private static final int INDEX_COLUMN_DELTA_CLUSTER_SECONDS = 21;
    private static final int INDEX_COLUMN_DELTA_CONCURRENCY_SECONDS = 19;
    private static final int INDEX_COLUMN_DELTA_DISK_READS = 17;
    private static final int INDEX_COLUMN_DELTA_BUFFER_GETS = 15;
    private static final int INDEX_COLUMN_DELTA_CPU_SECONDS = 12;
    private static final int INDEX_COLUMN_DELTA_ELAPSED_SECONDS = 9;
    private static final int INDEX_COLUMN_DELTA_EXECUTIONS = 7;
    private static final int INDEX_COLUMN_NUMBER_IDENTICAL_STATEMENTS = 6;
    private static final int INDEX_COLUMN_HAS_WAIT = 5;
    private static final int INDEX_COLUMN_HAS_PLAN = 4;
    private static final int INDEX_COLUMN_SQL_TEXT = 3;
    private static final int INDEX_COLUMN_INSTANCE = 2;
    private static final int INDEX_COLUMN_PARSING_SCHEMA = 1;
    private static final int INDEX_COLUMN_NO = 0;

    private static final int EXECUTION_PLANS_INDEX_ROW_TEMPLATE_STATEMENT_HEADER_ROW = 3;
    private static final int EXECUTION_PLANS_INDEX_ROW_TEMPLATE_CHILD_HEADER_ROW = 4;
    private static final int EXECUTION_PLANS_INDEX_ROW_TEMPLATE_EXECUTION_STEP_ROW = 5;
    private static final int EXECUTION_PLANS_INDEX_START_EXECUTION_PLANS = 6;

    private static final int WAIT_EVENTS_SQL_INDEX_ROW_TEMPLATE_STATEMENT_HEADER_ROW = 2;
    private static final int WAIT_EVENTS_SQL_INDEX_ROW_TEMPLATE_WAIT_EVENT_ROW = 3;
    private static final int WAIT_EVENTS_SQL_INDEX_START_WAIT_EVENTS = 4;

    private static final int WAIT_EVENTS_INDEX_ROW_TEMPLATE_WAIT_EVENT_ROW = 1;
    private static final int WAIT_EVENTS_INDEX_START_WAIT_EVENTS = 2;

    private static final String TEMPLATE_DELTA_V_SQL_AREA_XLSX = "Template_DELTA_V$SQLAREA.xlsx";

    private File destination;
    private DeltaSnapshot deltaSnapshot;
    private boolean moreExecutionPlans;
    private ProgressListener listener;

    private Sheet statementsSheet;
    private Sheet executionPlansSheet;
    private Sheet waitEventsForStatementSheet;
    private Sheet waitEventsForTimeSpanSheet;
    private CellStyle hyperlinkStyle;

    private DeltaSnapshotWriter(File destination, DeltaSnapshot deltaSnapshot, boolean moreExecutionPlans,
            ProgressListener listener) {
        this.destination = destination;
        this.deltaSnapshot = deltaSnapshot;
        this.moreExecutionPlans = moreExecutionPlans;
        this.listener = listener;
    }

    private boolean saveDeltaSnapshot() {
        try {
            Workbook workbook = WorkbookFactory
                    .create(this.getClass().getResourceAsStream(TEMPLATE_DELTA_V_SQL_AREA_XLSX));
            statementsSheet = workbook.getSheet("Delta V$SQLAREA");
            executionPlansSheet = workbook.getSheet("Execution Plans");
            waitEventsForStatementSheet = workbook.getSheet("Wait Events per SQL Statement");
            waitEventsForTimeSpanSheet = workbook.getSheet("All Wait Events");
            hyperlinkStyle = createHyperlinkStyle(workbook);

            writeDeltaSnapshotStatements();

            List<DeltaSQLStatementSnapshot> worstStatements = getWorstSQLStatements();

            try {
                writeExecutionPlansForWorstStatements(worstStatements);
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(null, e);
            }

            try {
                writeWaitEventsForWorstStatements(worstStatements);
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(null, e);
            }

            try {
                writeWaitEventsForTimeSpan();
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(null, e);
            }

            if (listener != null) {
                listener.informFinished();
            }

            OutputStream outputStream = new FileOutputStream(destination);
            workbook.write(outputStream);
            outputStream.close();

            return true;

        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, e);
            return false;
        }
    }

    private List<DeltaSQLStatementSnapshot> getWorstSQLStatements() {
        List<DeltaSQLStatementSnapshot> worstStatements;
        WorstStatementIdentifier wsi = new WorstStatementIdentifier(deltaSnapshot, moreExecutionPlans);

        // Identify the worst statements
        worstStatements = new ArrayList<>();
        int statementCount = 1;
        for (DeltaSQLStatementSnapshot currentSnapshot : deltaSnapshot.getDeltaSqlStatementSnapshots()) {

            if ((moreExecutionPlans && statementCount++ <= 100) || wsi.isAWorstStatement(currentSnapshot)) {
                worstStatements.add(currentSnapshot);
            }
        }
        return worstStatements;
    }

    public static boolean saveDeltaSnapshot(File destination, DeltaSnapshot deltaSnapshot,
            boolean moreExecutionPlans, ProgressListener listener) {
        DeltaSnapshotWriter writer = new DeltaSnapshotWriter(destination, deltaSnapshot, moreExecutionPlans,
                listener);
        return writer.saveDeltaSnapshot();
    }

    private CellStyle createHyperlinkStyle(Workbook workbook) {
        // cell style for hyperlinks
        // by default hyperlinks are blue and underlined
        CellStyle hyperlinkStyle = workbook.createCellStyle();
        hyperlinkStyle.cloneStyleFrom(statementsSheet.getRow(INDEX_ROW_TEMPLATE_DELTA_SQL_STATEMENT)
                .getCell(INDEX_COLUMN_SQL_TEXT).getCellStyle());

        Font hyperlinkFont = workbook.createFont();
        hyperlinkFont.setUnderline(Font.U_SINGLE);
        hyperlinkFont.setColor(IndexedColors.BLUE.getIndex());

        hyperlinkStyle.setFont(hyperlinkFont);

        return hyperlinkStyle;
    }

    private void writeDeltaSnapshotStatements() {
        Row templateRow = statementsSheet.getRow(INDEX_ROW_TEMPLATE_DELTA_SQL_STATEMENT);

        int currentRowIndex = INDEX_ROW_START_SQL_STATEMENTS;
        int currentNumber = 1;
        boolean snapshotContainsMissingBindVariables = false;

        if (listener != null) {
            listener.setMessage("Writing the statements...");
            listener.setStartValue(0);
            listener.setEndValue(deltaSnapshot.getDeltaSqlStatementSnapshots().size());
        }

        for (DeltaSQLStatementSnapshot currentSnapshot : deltaSnapshot.getDeltaSqlStatementSnapshots()) {
            if (listener != null) {
                listener.setCurrentValue(currentNumber);
            }

            Row currentRow = SSUtilities.copyRow(statementsSheet, templateRow, currentRowIndex);

            currentRow.getCell(INDEX_COLUMN_NO).setCellValue(currentNumber++);

            currentRow.getCell(INDEX_COLUMN_PARSING_SCHEMA)
                    .setCellValue(currentSnapshot.getSqlStatement().getParsingSchema());
            currentRow.getCell(INDEX_COLUMN_INSTANCE).setCellValue(currentSnapshot.getInstanceId());
            // Excel is limited to 32.767 chars per cell
            if (currentSnapshot.getSqlStatement() == null
                    || currentSnapshot.getSqlStatement().getSqlText() == null) {
                // The snapshot is no longer available in the library cache so there is no way to get it's SQL text
                currentRow.getCell(INDEX_COLUMN_SQL_TEXT)
                        .setCellValue("<Statement was swapped out of the library cache.>");
            } else {
                currentRow.getCell(INDEX_COLUMN_SQL_TEXT)
                        .setCellValue(currentSnapshot.getSqlStatement().getSqlTextTrimmedForExcel());
            }

            if (currentSnapshot.getDeltaNumberStatements() == null) {
                currentRow.getCell(INDEX_COLUMN_NUMBER_IDENTICAL_STATEMENTS).setCellValue(" ");
            } else {
                currentRow.getCell(INDEX_COLUMN_NUMBER_IDENTICAL_STATEMENTS)
                        .setCellValue(currentSnapshot.getDeltaNumberStatements().doubleValue());
                snapshotContainsMissingBindVariables = true;
            }

            currentRow.getCell(INDEX_COLUMN_DELTA_EXECUTIONS)
                    .setCellValue(currentSnapshot.getDeltaExecutions().doubleValue());

            currentRow.getCell(INDEX_COLUMN_DELTA_ELAPSED_SECONDS)
                    .setCellValue(currentSnapshot.getDeltaElapsedSeconds().doubleValue());
            currentRow.getCell(INDEX_COLUMN_DELTA_CPU_SECONDS)
                    .setCellValue(currentSnapshot.getDeltaCpuSeconds().doubleValue());

            currentRow.getCell(INDEX_COLUMN_DELTA_BUFFER_GETS)
                    .setCellValue(currentSnapshot.getDeltaBufferGets().doubleValue());
            currentRow.getCell(INDEX_COLUMN_DELTA_DISK_READS)
                    .setCellValue(currentSnapshot.getDeltaDiskReads().doubleValue());

            currentRow.getCell(INDEX_COLUMN_DELTA_CONCURRENCY_SECONDS)
                    .setCellValue(currentSnapshot.getDeltaConcurrencySeconds().doubleValue());
            currentRow.getCell(INDEX_COLUMN_DELTA_CLUSTER_SECONDS)
                    .setCellValue(currentSnapshot.getDeltaClusterSeconds().doubleValue());

            currentRow.getCell(INDEX_COLUMN_DELTA_ROWS_PROCESSED)
                    .setCellValue(currentSnapshot.getDeltaRowsProcessed().doubleValue());

            currentRow.getCell(INDEX_COLUMN_SQL_ID).setCellValue(currentSnapshot.getSqlStatement().getSqlId());

            currentRowIndex++;
        }

        if (!snapshotContainsMissingBindVariables) {
            // if there are no statements with missing bind variables this column is not needed.
            statementsSheet.setColumnHidden(INDEX_COLUMN_NUMBER_IDENTICAL_STATEMENTS, true);
        }

        // delete the template row
        SSUtilities.deleteRow(statementsSheet, templateRow);

        // update the formulas in the third row (sum)
        FormulaEvaluator evaluator = statementsSheet.getWorkbook().getCreationHelper().createFormulaEvaluator();
        Iterator<Cell> cellIterator = statementsSheet.getRow(INDEX_ROW_SUM_FORMULAS).cellIterator();
        while (cellIterator.hasNext()) {
            Cell currentCell = cellIterator.next();
            if (currentCell.getCellType() == Cell.CELL_TYPE_FORMULA) {
                evaluator.evaluateFormulaCell(currentCell);
            }
        }
    }

    private void writeExecutionPlansForWorstStatements(List<DeltaSQLStatementSnapshot> worstStatements) {
        Row templateStatementHeaderRow = executionPlansSheet
                .getRow(EXECUTION_PLANS_INDEX_ROW_TEMPLATE_STATEMENT_HEADER_ROW);
        Row templateChildHeaderRow = executionPlansSheet
                .getRow(EXECUTION_PLANS_INDEX_ROW_TEMPLATE_CHILD_HEADER_ROW);
        Row templateExecutionStepRow = executionPlansSheet
                .getRow(EXECUTION_PLANS_INDEX_ROW_TEMPLATE_EXECUTION_STEP_ROW);

        if (listener != null) {
            listener.setMessage("Loading the execution plans...");
        }
        SQLHelper.loadExecutionPlansForStatements(worstStatements, listener);

        // Now write the execution plans into the Excel sheet
        int currentRowIndex = EXECUTION_PLANS_INDEX_START_EXECUTION_PLANS;
        Row currentRow;

        int currentDataSet = 0;

        if (listener != null) {
            listener.setMessage("Writing the execution plans...");
            listener.setStartValue(0);
            listener.setEndValue(worstStatements.size());
        }

        for (DeltaSQLStatementSnapshot currentSnapshot : worstStatements) {

            currentDataSet++;
            if (listener != null) {
                listener.setCurrentValue(currentDataSet);
            }
            // Header for statement
            currentRow = SSUtilities.copyRow(executionPlansSheet, templateStatementHeaderRow, currentRowIndex);

            currentRow.getCell(0).setCellValue(currentSnapshot.getSqlStatement().getSqlId());
            currentRow.getCell(1).setCellValue(currentSnapshot.getSqlStatement().getSqlTextTrimmedForExcel());
            currentRowIndex++;

            // Link from sheet with statements to this execution plan
            Hyperlink link = statementsSheet.getWorkbook().getCreationHelper()
                    .createHyperlink(Hyperlink.LINK_DOCUMENT);
            // Later on we will delete three rows at the beginning of the sheet. Prepare the
            // hyperlink to point to the correct cell after the deletion.
            link.setAddress("'" + executionPlansSheet.getSheetName() + "'!A" + (currentRowIndex - 3));
            addLinkFromStatement(currentSnapshot.getSqlStatement().getSqlId(), INDEX_COLUMN_HAS_PLAN, link);

            for (ExecutionPlan currentPlan : currentSnapshot.getSqlStatement().getExecutionPlans()) {
                // Header for Child / Execution Plan
                // There may be more than one execution plans...
                currentRow = SSUtilities.copyRow(executionPlansSheet, templateChildHeaderRow, currentRowIndex);
                currentRow.getCell(0).setCellValue(currentPlan.getInstanceId());
                currentRow.getCell(1).setCellValue(currentPlan.getChildNumber());
                currentRowIndex++;

                currentRowIndex = writeExecutionPlanStepToExcel(templateExecutionStepRow, currentRowIndex,
                        currentPlan.getParentStep());
            }
        }

        // delete the template rows
        SSUtilities.deleteRow(executionPlansSheet, templateStatementHeaderRow);
        SSUtilities.deleteRow(executionPlansSheet, templateChildHeaderRow);
        SSUtilities.deleteRow(executionPlansSheet, templateExecutionStepRow);
    }

    private void addLinkFromStatement(String sqlId, int indexHyperlinkColumn, Hyperlink hyperlinkToCell) {

        int rowIndex = 1;
        while (rowIndex <= statementsSheet.getLastRowNum() && !statementsSheet.getRow(rowIndex)
                .getCell(INDEX_COLUMN_SQL_ID).getStringCellValue().equals(sqlId)) {
            rowIndex++;
        }

        if (statementsSheet.getRow(rowIndex).getCell(INDEX_COLUMN_SQL_ID).getStringCellValue().equals(sqlId)) {

            statementsSheet.getRow(rowIndex).getCell(indexHyperlinkColumn).setCellValue("X");
            statementsSheet.getRow(rowIndex).getCell(indexHyperlinkColumn).setHyperlink(hyperlinkToCell);
            statementsSheet.getRow(rowIndex).getCell(indexHyperlinkColumn).setCellStyle(hyperlinkStyle);
        }
    }

    private int writeExecutionPlanStepToExcel(Row templateForExecutionStepRow, int currentRowIndex,
            ExecutionPlanStep step) {

        int internalCurrentRowIndex = currentRowIndex;

        // Row for current step in the Execution Plan
        Row currentRow = SSUtilities.copyRow(executionPlansSheet, templateForExecutionStepRow, currentRowIndex);
        String operation = getIndentionAsString(step.getDepth()) + step.getOperation();
        if (step.getOptions() != null) {
            operation += " (" + step.getOptions() + ")";
        }
        currentRow.getCell(0).setCellValue(operation);
        if (step.getObjectOwner() != null) {
            currentRow.getCell(1).setCellValue(step.getObjectOwner() + "." + step.getObjectName());
        }
        nullSafeBigDecimalIntoCellWriter(currentRow.getCell(2), step.getCost());
        nullSafeBigDecimalIntoCellWriter(currentRow.getCell(3), step.getCardinality());
        nullSafeBigDecimalIntoCellWriter(currentRow.getCell(4), step.getBytes());
        nullSafeBigDecimalIntoCellWriter(currentRow.getCell(5), step.getCpuCost());
        nullSafeBigDecimalIntoCellWriter(currentRow.getCell(6), step.getIoCost());
        currentRow.getCell(7).setCellValue(step.getAccessPredicates());
        currentRow.getCell(8).setCellValue(step.getFilterPredicates());
        internalCurrentRowIndex++;

        for (ExecutionPlanStep childStep : step.getChildSteps()) {
            internalCurrentRowIndex = writeExecutionPlanStepToExcel(templateForExecutionStepRow,
                    internalCurrentRowIndex, childStep);
        }

        return internalCurrentRowIndex;
    }

    private void writeWaitEventsForWorstStatements(List<DeltaSQLStatementSnapshot> worstStatements) {

        Row templateStatementHeaderRow = waitEventsForStatementSheet
                .getRow(WAIT_EVENTS_SQL_INDEX_ROW_TEMPLATE_STATEMENT_HEADER_ROW);
        Row templateWaitEventRow = waitEventsForStatementSheet
                .getRow(WAIT_EVENTS_SQL_INDEX_ROW_TEMPLATE_WAIT_EVENT_ROW);

        Map<DeltaSQLStatementSnapshot, List<WaitEventForStatementTuple>> waitEventsPerStatementMap = SQLHelper
                .loadWaitEventsForStatements(worstStatements, deltaSnapshot.getSnapshotA().getSnapshotTime(),
                        deltaSnapshot.getSnapshotB().getSnapshotTime(), null);

        // Now write the wait events into the Excel sheet
        int currentRowIndex = WAIT_EVENTS_SQL_INDEX_START_WAIT_EVENTS;
        Row currentRow;

        int currentDataSet = 0;

        if (listener != null) {
            listener.setMessage("Writing the wait events...");
            listener.setStartValue(0);
            listener.setEndValue(worstStatements.size());
        }

        for (DeltaSQLStatementSnapshot currentSnapshot : worstStatements) {

            currentDataSet++;
            if (listener != null) {
                listener.setCurrentValue(currentDataSet);
            }

            if (waitEventsPerStatementMap.get(currentSnapshot) == null) {
                // if this worst statement has no wait events associated with, go to the next one
                continue;
            }

            // Header for statement
            currentRow = SSUtilities.copyRow(waitEventsForStatementSheet, templateStatementHeaderRow,
                    currentRowIndex);

            currentRow.getCell(0).setCellValue(currentSnapshot.getSqlStatement().getSqlId());
            currentRow.getCell(1).setCellValue(currentSnapshot.getSqlStatement().getSqlTextTrimmedForExcel());
            currentRowIndex++;

            // Link from sheet with statements to this list of wait events
            Hyperlink link = statementsSheet.getWorkbook().getCreationHelper()
                    .createHyperlink(Hyperlink.LINK_DOCUMENT);
            // Later on we will delete two rows at the beginning of the sheet. Prepare the
            // hyperlink to point to the correct cell after the deletion.
            link.setAddress("'" + waitEventsForStatementSheet.getSheetName() + "'!A" + (currentRowIndex - 2));
            addLinkFromStatement(currentSnapshot.getSqlStatement().getSqlId(), INDEX_COLUMN_HAS_WAIT, link);

            for (WaitEventForStatementTuple currentTuple : waitEventsPerStatementMap.get(currentSnapshot)) {
                currentRow = SSUtilities.copyRow(waitEventsForStatementSheet, templateWaitEventRow,
                        currentRowIndex);

                int columnIndex = 0;
                currentRow.getCell(columnIndex++).setCellValue(currentTuple.getWaitEventName());
                currentRow.getCell(columnIndex++).setCellValue(currentTuple.getWaitObjectOwner());
                currentRow.getCell(columnIndex++).setCellValue(currentTuple.getWaitObjectName());
                //noinspection UnusedAssignment
                nullSafeBigDecimalIntoCellWriter(currentRow.getCell(columnIndex++),
                        currentTuple.getWaitedSeconds());
                currentRowIndex++;
            }
        }

        // delete the template rows
        SSUtilities.deleteRow(waitEventsForStatementSheet, templateStatementHeaderRow);
        SSUtilities.deleteRow(waitEventsForStatementSheet, templateWaitEventRow);
    }

    private void writeWaitEventsForTimeSpan() {

        Row templateWaitEventRow = waitEventsForTimeSpanSheet.getRow(WAIT_EVENTS_INDEX_ROW_TEMPLATE_WAIT_EVENT_ROW);

        List<WaitEventForTimeSpanTuple> waitEventsList = SQLHelper.loadWaitEventsForTimeSpan(
                deltaSnapshot.getSnapshotA().getSnapshotTime(), deltaSnapshot.getSnapshotB().getSnapshotTime());

        // Now write the wait events into the Excel sheet
        int currentRowIndex = WAIT_EVENTS_INDEX_START_WAIT_EVENTS;
        Row currentRow;

        for (WaitEventForTimeSpanTuple currentWaitEvent : waitEventsList) {

            // Header for statement
            currentRow = SSUtilities.copyRow(waitEventsForTimeSpanSheet, templateWaitEventRow, currentRowIndex);

            int columnIndex = 0;
            currentRow.getCell(columnIndex++).setCellValue(currentWaitEvent.getWaitEventName());
            currentRow.getCell(columnIndex++).setCellValue(currentWaitEvent.getWaitObjectOwner());
            currentRow.getCell(columnIndex++).setCellValue(currentWaitEvent.getWaitObjectName());
            //noinspection UnusedAssignment
            nullSafeBigDecimalIntoCellWriter(currentRow.getCell(columnIndex++),
                    currentWaitEvent.getWaitedSeconds());

            currentRowIndex++;
        }

        // delete the template row
        SSUtilities.deleteRow(waitEventsForTimeSpanSheet, templateWaitEventRow);
    }

    private void nullSafeBigDecimalIntoCellWriter(Cell cell, BigDecimal value) {
        if (value == null) {
            cell.setCellValue("");
        } else {
            cell.setCellValue(value.doubleValue());
        }
    }

    private String getIndentionAsString(BigDecimal depth) {
        StringBuilder result = new StringBuilder("");

        for (int i = 1; i <= depth.intValue(); i++) {
            result.append("  ");
        }

        return result.toString();
    }

    // Is a statement a "worst statement"?
    // To find out, we need to look at this statement compared to all the
    // statements: A statement gets a worst statement, when it eats up a
    // big amount of runtime, CPU, buffer gets...
    private static class WorstStatementIdentifier {

        private boolean moreExecutionPlans;
        private BigDecimal sumExecutions = BigDecimal.ZERO;
        private BigDecimal sumElapsedSeconds = BigDecimal.ZERO;
        private BigDecimal sumCPUSeconds = BigDecimal.ZERO;
        private BigDecimal sumBufferGets = BigDecimal.ZERO;
        private BigDecimal sumDiskReads = BigDecimal.ZERO;

        public WorstStatementIdentifier(DeltaSnapshot deltaSnapshot, boolean moreExecutionPlans) {
            this.moreExecutionPlans = moreExecutionPlans;

            // Calculate and store some sums to compare against single statements
            for (DeltaSQLStatementSnapshot currentSnapshot : deltaSnapshot.getDeltaSqlStatementSnapshots()) {

                sumExecutions = sumExecutions.add(currentSnapshot.getDeltaExecutions());
                sumElapsedSeconds = sumElapsedSeconds.add(currentSnapshot.getDeltaElapsedSeconds());
                sumCPUSeconds = sumCPUSeconds.add(currentSnapshot.getDeltaCpuSeconds());
                sumBufferGets = sumBufferGets.add(currentSnapshot.getDeltaBufferGets());
                sumDiskReads = sumDiskReads.add(currentSnapshot.getDeltaDiskReads());
            }
        }

        public boolean isAWorstStatement(DeltaSQLStatementSnapshot snapshot) {
            // Implementation is analog to the conditional formatting in the
            // Excel sheet

            // more than 1 % of the total
            float percentThreshold = 1;
            if (moreExecutionPlans) {
                percentThreshold = 0.5f;
            }
            float multiplyFactor = 100.0f / percentThreshold;

            if (snapshot.getDeltaExecutions().multiply(new BigDecimal(multiplyFactor))
                    .compareTo(sumExecutions) > 0) {
                return true;
            }
            if (snapshot.getDeltaElapsedSeconds().multiply(new BigDecimal(multiplyFactor))
                    .compareTo(sumElapsedSeconds) > 0) {
                return true;
            }
            if (snapshot.getDeltaCpuSeconds().multiply(new BigDecimal(multiplyFactor))
                    .compareTo(sumCPUSeconds) > 0) {
                return true;
            }
            if (snapshot.getDeltaBufferGets().multiply(new BigDecimal(multiplyFactor))
                    .compareTo(sumBufferGets) > 0) {
                return true;
            }
            if (snapshot.getDeltaDiskReads().multiply(new BigDecimal(multiplyFactor)).compareTo(sumDiskReads) > 0) {
                return true;
            }
            if (snapshot.getDeltaExecutions().compareTo(BigDecimal.ZERO) > 0 && snapshot.getDeltaElapsedSeconds()
                    .divide(snapshot.getDeltaExecutions(), 1, BigDecimal.ROUND_HALF_UP)
                    .compareTo(BigDecimal.ONE) >= 0) {
                // average elapsed time at least 1 second
                return true;
            }

            return false;
        }
    }
}