Question

Avoir du mal à identifier pourquoi la durée d'une requête diminuerait lors de l'utilisation OPTION (HASH JOIN) ou OPTION (MERGE JOIN), bien que le coût du plan augmente.

Arrière plan

J'ai une base de données de rapport utilisant le schéma d'étoiles traditionnel (tables de dimension / fait). SQL est généré par ORM dans l'outil BI. J'ai une certaine flexibilité avec le SQL généré en termes d'ajout de conseils d'optimiseur, mais c'est tout (pas de refactorisation de requête, etc.).

Problème

Lorsque la requête ci-dessous est exécutée sans indice d'optimiseur, la durée moyenne est d'environ 90 secondes et le coût du sous-arbre estimé est d'environ 2,9. Lorsqu'il est exécuté avec le OPTION (MERGE JOIN) ou OPTION (HASH JOIN) Des conseils, la durée moyenne est d'environ 3 secondes, mais le coût estimé du sous-arbre est d'environ 4,9.

J'ai vérifié que les statistiques sur les tables affectées sont à jour en utilisant UPDATE STATISTICS <schema>.<table> WITH FULLSCAN;. Des index ont également été ajoutés sur la base de recommandations d'optimiseur.

Voici la requête (oui, c'est moche, voir ORM Commentaire ci-dessus):

SELECT  a11.trans_00_key  TRANS_00_KEY,
    a11.region_id  REGION_ID,
    Max(a15.region_cd)  REGION_CD,
    a11.state_id  STATE_ID,
    Max(a13.district_cd)  DISTRICT_CD,
    a12.cntrct_nbr  CNTRCT_NBR,
    a11.proj_nbr  PROJ_NBR,
    Max(a11.proj_nbr)  PROJ_NBR0,
    CONVERT(DATETIME, CONVERT(VARCHAR(10), (a12.sys_date_yr + '-' + a12.sys_date_mon + '-01'), 101))  CustCol_5,
    a12.proj_ctgry_nbr  PROJ_CTGRY_NBR,
    a11.type_of_work  TYPE_OF_WORK,
    a11.funct_rng  FUNCT_RNG,
    Isnull(a11.fis_id, -1)  FIS_ID,
    Max(Isnull(a14.fis_dscr, 'Blank'))  FIS_DSCR,
    CASE WHEN a12.bid_amount > 1 THEN a12.bid_amount ELSE a12.eng_est_amt END  CustCol_7,
    Sum(a11.est_amt)  WJXBFS1,
    (Sum(a11.ltd_amt) - (Sum(a11.ltd_ind_bill_cst) + Sum(a11.ltd_ind_non_bill_cst)))  WJXBFS2,
    Sum(a11.ltd_cost_cntrct)  WJXBFS3,
    ((Sum(a11.ltd_amt) - (Sum(a11.ltd_ind_bill_cst) + Sum(a11.ltd_ind_non_bill_cst))) - Sum(a11.ltd_cost_cntrct))  WJXBFS4,
    (Sum(a11.est_amt) - (Sum(a11.ltd_amt) - (Sum(a11.ltd_ind_bill_cst) + Sum(a11.ltd_ind_non_bill_cst))))  WJXBFS5
FROM    sys_trans_detail_fact   a11
    JOIN    sys_trans_hdr_fact  a12
      ON    (a11.proj_nbr = a12.proj_nbr AND
    a11.trans_00_key = a12.trans_00_key AND
    a11.state_id = a12.state_id)
    JOIN    district_lkp    a13
      ON    (a11.state_id = a13.state_id)
    JOIN    fis_lkp a14
      ON    (Isnull(a11.fis_id, -1) = Isnull(a14.fis_id, -1))
    JOIN    region_lkp  a15
      ON    (a11.region_id = a15.region_id)
WHERE   (((a11.trans_00_key)
 IN (SELECT r12.trans_00_key
    FROM    sys_trans_detail_fact   r12
    WHERE   r12.fund_src_name_id IN (3, 7, 5)))
 AND a11.fund_src_name_id IN (6, 8, 2, 3, 7, 5, 4)
 AND a11.state_id IN (8, 4, 19, 14, 20, 23, 17, 25, 16, 18, 24, 2, 12, 22, 5, 11, 6, 1, 21, 7, 15, 10, 9, 3, 13, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36)
 AND a11.status_id = 1
 AND a11.extract_dttm IN (CONVERT(DATETIME, '2012-09-01 00:00:00', 120))
 AND a11.cost_cat_id IN (10, 4))
GROUP BY    a11.trans_00_key,
    a11.region_id,
    a11.state_id,
    a12.cntrct_nbr,
    a11.proj_nbr,
    CONVERT(DATETIME, CONVERT(VARCHAR(10), (a12.sys_date_yr + '-' + a12.sys_date_mon + '-01'), 101)),
    a12.proj_ctgry_nbr,
    a11.type_of_work,
    a11.funct_rng,
    Isnull(a11.fis_id, -1),
    CASE WHEN a12.bid_amount > 1 THEN a12.bid_amount ELSE a12.eng_est_amt END

Plan d'exécution réel sans indice

Je suis confus quant à la raison pour laquelle le plan montre 572 millions de lignes réelles pour l'indice recherché en rouge.

Execution plan, no hints

Plan d'exécution réel en utilisant OPTION (HASH JOIN) indice

Execution plan, hash join hint

J'ai lu que les conseils d'optimiseur sont un dernier recours après la vérification des indices appropriés appliqués et que les statistiques sont vérifiées à jour. Dans ce cas, SQL Server semble choisir le meilleur plan en fonction du coût, mais il y a une pénalité significative (environ 87 secondes) en termes de durée de la requête. Cela ressemble-t-il à un cas où l'indice Optimizer doit être utilisé? Sinon, quels autres articles dois-je vérifier pour s'assurer que l'optimiseur choisit le meilleur plan de coût et de durée?

Pas de solution correcte

Licencié sous: CC-BY-SA avec attribution
Non affilié à dba.stackexchange
scroll top