Mysql无法识别正确的执行计划

时间:2016-11-01 22:57:20

标签: mysql stored-procedures

我正在为ETL构建存储过程。在存储过程中,创建一个表,并在下一个查询中将同一个表用作两个实例(使用具有两个别名的相同表)。由于第二个查询需要花费大量时间,因此我查看了执行计划并执行了没有存储过程的查询。在没有存储过程的情况下执行第二个查询在合理的时间内按预期运行。

以下是两个查询。

QUERY_1:

CREATE TABLE TMPRPT_STBDEX_SALE_BDM_$tblname (
    SALE_JOURNAL_ID BIGINT(20) NULL DEFAULT NULL,
    DEBTOR_CONSULTANT_RELATIONSHIP_ID INT(11) NULL DEFAULT '0',
    DISPLAY_ORDER INT(11) NULL DEFAULT NULL,
    INDEX IDX_SALE_JOURNAL_ID (SALE_JOURNAL_ID),
    INDEX IDX_DEBCONS_ID (DEBTOR_CONSULTANT_RELATIONSHIP_ID),
    INDEX IDX_DISPLAY_ORDER (DISPLAY_ORDER)
)
ENGINE=InnoDB
;

INSERT INTO TMPRPT_STBDEX_SALE_BDM_$tblname
    SELECT DISTINCT
        TSS.SALE_JOURNAL_ID,
        RDC.DEBTOR_CONSULTANT_RELATIONSHIP_ID,
        RDC.DISPLAY_ORDER
    FROM
        TMPRPT_STBDEX_SALE_BOOKING_$tblname TSS

        LEFT OUTER JOIN BOOKING RB
            ON (RB.BOOKING_ID = TSS.BOOKING_ID)
        LEFT OUTER JOIN BOOKING_DEPT_LEVELS BDL
            ON (BDL.BOOKING_ID = RB.BOOKING_ID)
        LEFT OUTER JOIN TMPRPT_STBDEX_SEGMENT_$tblname RS
            ON (RS.SEGMENT_ID = TSS.SEGMENT_ID)

        LEFT OUTER JOIN DEBTOR_CONSULTANT_RELATIONSHIP RDC
            ON (RDC.DEBTOR_ID = RB.DEBTOR_ID AND
                RDC.CONSULTANT_ID IS NOT NULL AND
                RDC.CONSULTANT_TYPE_CODE = 'BUSINESS_DEVELOPMENT' AND
                RDC.COMMISSION_PERCENTAGE IS NOT NULL AND
                (RDC.DOMESTIC_INTERNATIONAL_CODE = 'BOTH' OR CASE WHEN RDC.DOMESTIC_INTERNATIONAL_CODE = 'DOMESTIC' THEN 1 = RS.IDT_NUMBER ELSE 1 <> RS.IDT_NUMBER END ) AND
                RDC.START_DATE <= TSS.TRANSACTION_DATE AND
                (RDC.FINISH_DATE IS NULL OR RDC.FINISH_DATE >= TSS.TRANSACTION_DATE))
        LEFT OUTER JOIN COST_CENTRE_DEBTOR_CONSULTANT_RELATIONSHIP CCDCR
            ON (CCDCR.DEBTOR_CONSULTANT_RELATIONSHIP_ID = RDC.DEBTOR_CONSULTANT_RELATIONSHIP_ID AND CCDCR.COST_CENTRE_ID = RB.COST_CENTRE_ID)
        LEFT OUTER JOIN DEPARTMENT_DEBTOR_CONSULTANT_RELATIONSHIP DDCR
            ON (DDCR.DEBTOR_CONSULTANT_RELATIONSHIP_ID = RDC.DEBTOR_CONSULTANT_RELATIONSHIP_ID AND
                (DDCR.DEPARTMENT_ID = BDL.LEVEL0 OR 
                DDCR.DEPARTMENT_ID = BDL.LEVEL1 OR
                DDCR.DEPARTMENT_ID = BDL.LEVEL2 OR
                DDCR.DEPARTMENT_ID = BDL.LEVEL3 OR
                DDCR.DEPARTMENT_ID = BDL.LEVEL4 OR
                DDCR.DEPARTMENT_ID = BDL.LEVEL5))
    WHERE
        (RDC.DISPLAY_ORDER = 1 OR RDC.DISPLAY_ORDER = 2) AND
        (RDC.HAS_ALL_PERMISSION = 'Y' OR
        (CCDCR.COST_CENTRE_ID IS NOT NULL AND DDCR.DEPARTMENT_ID IS NOT NULL)); 

Query_2:

SELECT
        RSAL.SALE_JOURNAL_ID,
        RS.COSTING_ID,
        RD.DEBTOR_CODE,
        CONCAT('B.',LPAD(CAST(RB.BOOKING_ID AS CHAR),10,'0')) AS BOOKING_REFERENCE,
        RS.SEGMENT_ID,
        DOC.DOCUMENT_REF_NUMBER AS INVOICE_NO,
        RCON.NAME AS CONSULTANT_NAME,
        COALESCE(RSPS.LEAD_PASSENGER_NAME, RCL.PROFILE_NAME) AS COSTING_PASSENGER,
        RBR.CODE AS BRANCH_CODE,
        RS.SEGMENT_SHORT_CODE,
        (CASE WHEN RS.IDT_NUMBER = 1 THEN
            'D'
            WHEN RS.IDT_NUMBER = 2 THEN
            'T'
            WHEN RS.IDT_NUMBER = 3 THEN
            'I'
            ELSE NULL
            END) AS DOM_INT,

        (CASE WHEN RSAL.COSTING_PAYMENT_TYPE_CODE = 'PAY_DIRECT' THEN 0 ELSE 
            RSAL.SUPPLIER_RATES_EXCL_GST +
            RSAL.SUPPLIER_RATES_GST_FREE +
            RSAL.SUPPLIER_CHARGES_EXCL_COMMISSION +
            RSAL.SUPPLIER_CHARGES_COMMISSION_FREE +
            RSAL.SUPPLIER_FEES_EXCL_GST +
            RSAL.TAX_AMOUNT_EXCL_GST_CALCULATED +
            RSAL.TAX_AMOUNT_GST_FREE +
            RSAL.AGENCY_MARKUP_EXCL_GST_CALCULATED +
            RSAL.AGENCY_DISCOUNT_EXCL_GST_CALCULATED
        END) AS GROSS_SALES,

        (CASE WHEN RSAL.COSTING_PAYMENT_TYPE_CODE = 'PAY_DIRECT' THEN 
            RSAL.SUPPLIER_RATES_EXCL_GST +
            RSAL.SUPPLIER_RATES_GST_FREE +
            RSAL.SUPPLIER_CHARGES_EXCL_COMMISSION +
            RSAL.SUPPLIER_CHARGES_COMMISSION_FREE +
            RSAL.SUPPLIER_FEES_EXCL_GST +
            RSAL.TAX_AMOUNT_EXCL_GST_CALCULATED +
            RSAL.TAX_AMOUNT_GST_FREE +
            RSAL.AGENCY_MARKUP_EXCL_GST_CALCULATED +
            RSAL.AGENCY_DISCOUNT_EXCL_GST_CALCULATED
        ELSE 0 END) AS PD_SALES,

        (CASE WHEN RSAL.COSTING_PAYMENT_TYPE_CODE = 'PAY_DIRECT' THEN 0 ELSE RSAL.SERVICES_CREDITOR_COMMISSION_AMOUNT_EXCL_GST_CALCULATED - (RS.COSTING_MERCHANT_FEE_POSTED_EXCL_GST * (SIGN(RSAL.SERVICES_CREDITOR_COMMISSION_AMOUNT_EXCL_GST_CALCULATED + RSAL.SUPPLIER_RATES_EXCL_GST))) END) AS EARNED_COMM,
        (CASE WHEN RSAL.COSTING_PAYMENT_TYPE_CODE = 'PAY_DIRECT' THEN RSAL.SERVICES_CREDITOR_COMMISSION_AMOUNT_EXCL_GST_CALCULATED - (RS.COSTING_MERCHANT_FEE_POSTED_EXCL_GST * (SIGN(RSAL.SERVICES_CREDITOR_COMMISSION_AMOUNT_EXCL_GST_CALCULATED + RSAL.SUPPLIER_RATES_EXCL_GST))) ELSE 0 END) AS PD_COMM,
        RSAL.OVERRIDE_AMOUNT_POSTED_EXCL_GST AS OVERRIDE_COMM,

        (CASE
            WHEN RDMF.DEBTOR_MANAGEMENT_FEE_ID IS NULL THEN 0
            WHEN RDMF.FEE_AMOUNT_TYPE = 'PERCENTAGE' 
            THEN 
                (RDMF.FEE_AMOUNT / 100.00) * 
                (RSAL.SUPPLIER_RATES_EXCL_GST +
                RSAL.SUPPLIER_RATES_GST_FREE +
                RSAL.SUPPLIER_CHARGES_EXCL_COMMISSION +
                RSAL.SUPPLIER_CHARGES_COMMISSION_FREE)
            WHEN RDMF.FEE_AMOUNT_TYPE = 'DOLLAR_INCL_GST'
            THEN (RDMF.FEE_AMOUNT / ((100.00 + RAGN.GST_PERCENTAGE) / 100.00))
            ELSE
                RDMF.FEE_AMOUNT
        END) AS RETENTIONS,

        (RS.COSTING_SPECULATIVE_MERCHANT_FEE_POSTED_EXCL_GST * SIGN(RSAL.SERVICES_CREDITOR_COMMISSION_AMOUNT_EXCL_GST_CALCULATED + RSAL.SUPPLIER_RATES_EXCL_GST)) AS MERCHANT_FEE,

        CONS.NAME AS BDM1_NAME,
        RDC.COMMISSION_PERCENTAGE AS BDM1_PERCENTAGE,
        CONS2.NAME AS BDM2_NAME,
        RDC2.COMMISSION_PERCENTAGE AS BDM2_PERCENTAGE

    FROM
        TMPRPT_STBDEX_SALE_BOOKING_$tblname TSS

        LEFT OUTER JOIN SALE_JOURNAL RSAL
            ON (RSAL.SALE_JOURNAL_ID = TSS.SALE_JOURNAL_ID)

        LEFT OUTER JOIN AGENCY RAGN
            ON (RAGN.AGENCY_ID = 1)

        LEFT OUTER JOIN TMPRPT_STBDEX_SEGMENT_$tblname RS
            ON (RS.COSTING_ID = RSAL.COSTING_ID)
        LEFT OUTER JOIN BOOKING RB
            ON (RB.BOOKING_ID = RS.BOOKING_ID)
        LEFT OUTER JOIN DEBTOR RD
            ON (RD.DEBTOR_ID = RB.DEBTOR_ID)
        LEFT OUTER JOIN TRANSACTION_JOURNAL RTJ
            ON (RTJ.TRANSACTION_JOURNAL_ID = RSAL.TRANSACTION_JOURNAL_ID)
        LEFT OUTER JOIN TRANSACTION_JOURNAL_LINKS TJL
            ON (TJL.TRANSACTION_JOURNAL_ID = RTJ.TRANSACTION_JOURNAL_ID)    
        LEFT OUTER JOIN INVOICE RI
            ON (RI.INVOICE_ID = TJL.INVOICE_ID)
        LEFT OUTER JOIN DOCUMENT DOC 
            ON (RI.DOCUMENT_ID = DOC.DOCUMENT_ID)
        LEFT OUTER JOIN CONSULTANT RCON
            ON (RCON.CONSULTANT_ID = RB.PREF_CONSULTANT1_ID)
        LEFT OUTER JOIN SEGMENT_PASSENGER_SUMMARY RSPS
            ON (RSPS.SEGMENT_ID = RS.SEGMENT_ID)
        LEFT OUTER JOIN BRANCH RBR
            ON (RBR.BRANCH_ID = RB.LVL1_BRANCH_ID)
        LEFT OUTER JOIN CLIENT RCL
            ON (RCL.CLIENT_ID = RB.CLIENT_ID)
        LEFT OUTER JOIN DEBTOR_MANAGEMENT_FEE RDMF
            ON (RDMF.DEBTOR_ID = RD.DEBTOR_ID AND
                RDMF.SEGMENT_TYPE = RS.SEGMENT_TYPE_CODE AND
                (RDMF.AIRLINE_CODE = RS.AIR_AIRLINE_CODE OR RDMF.SEGMENT_TYPE <> 'TICKET') AND
                (RDMF.INT_DOM = CASE WHEN RS.IDT_NUMBER = 1 THEN 'DOMESTIC' ELSE 'INTERNATIONAL' END) AND
                (RDMF.TERMINATION_DATE IS NULL OR RDMF.TERMINATION_DATE > CURDATE()))
        LEFT OUTER JOIN TMPRPT_STBDEX_SALE_BDM_$tblname TSSB
            ON (TSSB.SALE_JOURNAL_ID = RSAL.SALE_JOURNAL_ID AND TSSB.DISPLAY_ORDER = 1) 
        LEFT OUTER JOIN DEBTOR_CONSULTANT_RELATIONSHIP RDC
            ON (RDC.DEBTOR_CONSULTANT_RELATIONSHIP_ID = TSSB.DEBTOR_CONSULTANT_RELATIONSHIP_ID AND
                (RDC.CONSULTANT_ID = ParamBDMConsultant OR ParamBDMConsultant IS NULL))
        LEFT OUTER JOIN CONSULTANT CONS ON (CONS.CONSULTANT_ID = RDC.CONSULTANT_ID)
        LEFT OUTER JOIN TMPRPT_STBDEX_SALE_BDM_$tblname TSSB2
            ON (TSSB2.SALE_JOURNAL_ID = RSAL.SALE_JOURNAL_ID AND TSSB2.DISPLAY_ORDER = 2) 
        LEFT OUTER JOIN DEBTOR_CONSULTANT_RELATIONSHIP RDC2
            ON (RDC2.DEBTOR_CONSULTANT_RELATIONSHIP_ID = TSSB2.DEBTOR_CONSULTANT_RELATIONSHIP_ID AND
                (RDC2.CONSULTANT_ID = ParamBDMConsultant OR ParamBDMConsultant IS NULL))
        LEFT OUTER JOIN CONSULTANT CONS2 ON (CONS2.CONSULTANT_ID = RDC2.CONSULTANT_ID)

    WHERE
        (ParamBDMConsultant IS NULL OR RDC.CONSULTANT_ID = ParamBDMConsultant) AND
        (ParamExcludeCostingsWithoutBDM = 'No' OR RDC.CONSULTANT_ID IS NOT NULL)
    GROUP BY 
        RSAL.SALE_JOURNAL_ID;

请注意,Query_1中创建的 TMPRPT_STBDEX_SALE_BDM_ $ tblname 在Query_2中使用了两次。

以下是Query_2的执行计划

Execution Plan for Query_2 when executed with in stored proc

Execution Plan for Query_2 when executed manually with out stored proc

请注意在Query_1中创建Table的突出显示行。当类型为 ref 且识别出正确的索引时,我不明白为什么它会扫描整个表格。

通过在填充表格后更改为Query_1中的表创建索引到 Alter表添加索引index_name 的方式,我能够解决此问题。这解决了我的问题。

还可以通过将Query_1中的数据集分成两个表并使用它们代替Query_2中的单个表来解决此问题。

对我而言,由于收集统计信息的延迟,似乎mysql没有选择正确的执行计划。

有人可以解释为什么会这样吗?

Mysql版本:5.6

0 个答案:

没有答案