2010-02-04 12 views
1

Cette requête provenait à l'origine d'un programme VB6 accédant aux tables MS Access qui sont liées à des bases de données externes via ODBC. Il faut environ 3h30 pour courir.Requête lente dans SQL Server 2008 à l'aide du serveur lié. Que puis-je regarder?

Maintenant, j'ai configuré une boîte SQL Server 2008 Express pour évaluer comment nous pouvons migrer vers un meilleur système de base de données. J'ai donc installé un serveur lié sur le serveur externe (nous l'appelons DWPROD) et quand j'ai converti la requête (j'ai changé les instructions iif en casse) et que je l'ai exécuté, je l'ai laissé fonctionner pendant 12 minutes. Je suis nouveau sur SQL Server, alors que puis-je regarder pour voir ce qui prend si longtemps? Des suggestions pour accélérer cela? Des ressources sont-elles recommandées pour que je puisse en apprendre plus à ce sujet? C'est une requête simple comparée à ce que nous avons, donc je vais recommencer ce problème.

Requête:

SELECT [FISCAL_YEAR] AS FISCAL_YEAR, 
[Budgets].[dbo].[Departments].strdepentity AS ENTITY_CODE, 
[Budgets].[dbo].[Departments].depdiv1 AS DIVISION_CODE, 
FINANCIAL_DEPTID AS DEPTID, 
FUND_CODE, 
[CLASS_FLD] AS CLASS_CODE, 
[PROJECT_ID], 
[PROGRAM_CODE], 
[ACCOUNT] AS ACCOUNT_CODE, 
CASE 
    WHEN [ACCOUNT] in ('500020','520000','520220','520240') THEN 2 
    WHEN LEFT([ACCOUNT],1)='5' THEN 1 
    WHEN Left([ACCOUNT],1)='6' THEN 3 
    WHEN Left([ACCOUNT],1)='7' THEN 4 
    WHEN Left([ACCOUNT],1)='8' THEN 5 
    ELSE 0 
    END AS ACCT_GRP_CODE, 
Sum([BUDGET_AMOUNT]) AS GL_BUD_AMT, 
Sum([ENCUMBRANCE_AMOUNT]) AS GL_ENC_AMT, 
Sum([EXPENDITURE_AMOUNT]) AS GL_EXP_AMT, 
CASE 
    WHEN Left([CLASS_FLD],2)='12' THEN 0 
    WHEN Left([CLASS_FLD],3)='113' THEN 3 
    WHEN Left([CLASS_FLD],3)='112' THEN 14 
    WHEN Left([CLASS_FLD],3)='115' THEN 10 
    WHEN Left([CLASS_FLD],3)='116' THEN 13 
    WHEN Left([CLASS_FLD],3)='117' THEN 12 
    WHEN Left([CLASS_FLD],3)='118' THEN 11 
    WHEN Left([CLASS_FLD],2)='13' THEN 2 
    WHEN Left([CLASS_FLD],2)='14' THEN 3 
    WHEN Left([CLASS_FLD],1)='4' THEN 4 
    WHEN Left([CLASS_FLD],1)='6' THEN 6 
    ELSE 9 
    END AS FUND_SOURCE 

FROM [DWPROD]..[DISC].[PS_LEDGER_DETAIL] LEFT JOIN [Budgets].[dbo].[Departments] ON FINANCIAL_DEPTID=[Budgets].[dbo].[Departments].deporg 
WHERE ((([BUDGET_PERIOD])='2010') And (([ACCOUNTING_PERIOD]) Between 1 And 12)) 


GROUP BY 
[FISCAL_YEAR], 
[Budgets].[dbo].[Departments].strdepentity, [Budgets].[dbo].[Departments].depdiv1, 
[FINANCIAL_DEPTID], 
FUND_CODE, 
[CLASS_FLD], 
[PROJECT_ID], 
[PROGRAM_CODE], 
[ACCOUNT], 
CASE 
    WHEN [ACCOUNT] in ('500020','520000','520220','520240') THEN 2 
    WHEN LEFT([ACCOUNT],1)='5' THEN 1 
    WHEN Left([ACCOUNT],1)='6' THEN 3 
    WHEN Left([ACCOUNT],1)='7' THEN 4 
    WHEN Left([ACCOUNT],1)='8' THEN 5 
    ELSE 0 
    END, 
    CASE 
    WHEN Left([CLASS_FLD],2)='12' THEN 0 
    WHEN Left([CLASS_FLD],3)='113' THEN 3 
    WHEN Left([CLASS_FLD],3)='112' THEN 14 
    WHEN Left([CLASS_FLD],3)='115' THEN 10 
    WHEN Left([CLASS_FLD],3)='116' THEN 13 
    WHEN Left([CLASS_FLD],3)='117' THEN 12 
    WHEN Left([CLASS_FLD],3)='118' THEN 11 
    WHEN Left([CLASS_FLD],2)='13' THEN 2 
    WHEN Left([CLASS_FLD],2)='14' THEN 3 
    WHEN Left([CLASS_FLD],1)='4' THEN 4 
    WHEN Left([CLASS_FLD],1)='6' THEN 6 
    ELSE 9 
    END 
HAVING (((FISCAL_YEAR)=2010) 
AND ((FINANCIAL_DEPTID) Between '100' And '999') 
AND ((ACCOUNT) Between '500000' And '899999')) 
ORDER BY [FINANCIAL_DEPTID], [CLASS_FLD], [PROJECT_ID], [ACCOUNT] 

Je sais que c'est long. Merci d'avoir regardé.

+0

Quel est le DWPROD serveur lié? Toujours accès? – MartW

+0

DWPROD est le serveur lié. Dans cette requête, aucune table d'accès n'est touchée. Le dbo.Departments est une table sur notre SQL Server. –

Répondre

3

Je re-écrit votre requête:.

WITH ledger_detail AS (
     SELECT pld.fiscal_year, 
      pld.financial_deptid AS DEPTID, 
      pld.fund_code, 
      pld.class_fld AS CLASS_CODE, 
      pld.project_id, 
      pld.program_code, 
      CASE 
       WHEN pld.account IN ('500020','520000','520220','520240') THEN 2 
       WHEN LEFT(pld.account,1) = '5' THEN 1 
       WHEN LEFT(pld.account,1) = '6' THEN 3 
       WHEN LEFT(pld.account,1) = '7' THEN 4 
       WHEN LEFT(pld.account,1) = '8' THEN 5 
       ELSE 0 
      END AS ACCT_GRP_CODE, 
      pld.budget_amount, 
      pld.encumbrance_amount, 
      pld.expenditure_amount, 
      pld.account AS ACCOUNT_CODE, 
      CASE 
       WHEN LEFT(pld.class_fld, 2) ='12' THEN 0 
       WHEN LEFT(pld.class_fld, 3)='113' THEN 3 
       WHEN LEFT(pld.class_fld, 3)='112' THEN 14 
       WHEN LEFT(pld.class_fld, 3)='115' THEN 10 
       WHEN LEFT(pld.class_fld, 3)='116' THEN 13 
       WHEN LEFT(pld.class_fld, 3)='117' THEN 12 
       WHEN LEFT(pld.class_fld, 3)='118' THEN 11 
       WHEN LEFT(pld.class_fld, 2)='13' THEN 2 
       WHEN LEFT(pld.class_fld, 2)='14' THEN 3 
       WHEN LEFT(pld.class_fld, 1)='4' THEN 4 
       WHEN LEFT(pld.class_fld, 1)='6' THEN 6 
       ELSE 9 
      END AS FUND_SOURCE 
     FROM [DWPROD]..[DISC].[PS_LEDGER_DETAIL] pld 
     WHERE pld.budget_period = '2010' 
     AND pld.accounting_period BETWEEN 1 AND 12 
     AND pld.fiscal_year = 2010 
     AND pld.financial_deptid BETWEEN '100' AND '999' 
     AND pld.account BETWEEN '500000' AND '899999') 
    SELECT x.fiscal_year, 
      y.strdepentity AS ENTITY_CODE, 
      y.depdiv1 AS DIVISION_CODE, 
      x.deptid, 
      x.fund_code, 
      x.class_code, 
      x.project_id, 
      x.program_code, 
      x.acct_grp_code, 
      SUM(x.budget_amount) AS GL_BUD_AMT, 
      SUM(x.encumbrance_amount) AS GL_ENC_AMT, 
      SUM(x.expenditure_amount) AS GL_EXP_AMT, 
      x.account AS ACCOUNT_CODE, 
      x.fund_source 
    FROM ledger_detail x 
LEFT JOIN [Budgets].[dbo].[Departments] y ON y.deporg = x.financial_deptid  
GROUP BY x.fiscal_year, y.strdepentity, y.depdiv1, x.deptid, x.fund_code, x.class_code, x.project_id, x.program_code, x.acct_grp_code 
ORDER BY x.financial_deptid, x.class_fld, x.project_id, x.account 

Même si vous avez des index sur [DWPROD] .. [DISQUE] [PS_LEDGER_DETAIL] 's account et class_fld, l'utilisation d'une fonction (LEFT) sur eux les rend inutilisables pour cette requête.

En outre, vous incluez les critères de filtrage dans la clause HAVING plutôt que dans la clause WHERE.

MISE À JOUR: Non-CTE équivalent

SELECT x.fiscal_year, 
      y.strdepentity AS ENTITY_CODE, 
      y.depdiv1 AS DIVISION_CODE, 
      x.deptid, 
      x.fund_code, 
      x.class_code, 
      x.project_id, 
      x.program_code, 
      x.acct_grp_code, 
      SUM(x.budget_amount) AS GL_BUD_AMT, 
      SUM(x.encumbrance_amount) AS GL_ENC_AMT, 
      SUM(x.expenditure_amount) AS GL_EXP_AMT, 
      x.account AS ACCOUNT_CODE, 
      x.fund_source 
    FROM (SELECT pld.fiscal_year, 
        pld.financial_deptid AS DEPTID, 
        pld.fund_code, 
        pld.class_fld AS CLASS_CODE, 
        pld.project_id, 
        pld.program_code, 
        CASE 
        WHEN pld.account IN ('500020','520000','520220','520240') THEN 2 
        WHEN LEFT(pld.account,1) = '5' THEN 1 
        WHEN LEFT(pld.account,1) = '6' THEN 3 
        WHEN LEFT(pld.account,1) = '7' THEN 4 
        WHEN LEFT(pld.account,1) = '8' THEN 5 
        ELSE 0 
        END AS ACCT_GRP_CODE, 
        pld.budget_amount, 
        pld.encumbrance_amount, 
        pld.expenditure_amount, 
        pld.account AS ACCOUNT_CODE, 
        CASE 
        WHEN LEFT(pld.class_fld, 2) ='12' THEN 0 
        WHEN LEFT(pld.class_fld, 3)='113' THEN 3 
        WHEN LEFT(pld.class_fld, 3)='112' THEN 14 
        WHEN LEFT(pld.class_fld, 3)='115' THEN 10 
        WHEN LEFT(pld.class_fld, 3)='116' THEN 13 
        WHEN LEFT(pld.class_fld, 3)='117' THEN 12 
        WHEN LEFT(pld.class_fld, 3)='118' THEN 11 
        WHEN LEFT(pld.class_fld, 2)='13' THEN 2 
        WHEN LEFT(pld.class_fld, 2)='14' THEN 3 
        WHEN LEFT(pld.class_fld, 1)='4' THEN 4 
        WHEN LEFT(pld.class_fld, 1)='6' THEN 6 
        ELSE 9 
        END AS FUND_SOURCE 
      FROM [DWPROD]..[DISC].[PS_LEDGER_DETAIL] pld 
      WHERE pld.budget_period = '2010' 
       AND pld.accounting_period BETWEEN 1 AND 12 
       AND pld.fiscal_year = 2010 
       AND pld.financial_deptid BETWEEN '100' AND '999' 
       AND pld.account BETWEEN '500000' AND '899999') x 
LEFT JOIN [Budgets].[dbo].[Departments] y ON y.deporg = x.financial_deptid  
GROUP BY x.fiscal_year, y.strdepentity, y.depdiv1, x.deptid, x.fund_code, x.class_code, x.project_id, x.program_code, x.acct_grp_code 
ORDER BY x.financial_deptid, x.class_fld, x.project_id, x.account 
+0

Laissez-moi voir si je comprends cela. La clause with sélectionne et crée une table en mémoire, à laquelle nous pouvons nous joindre. Si c'est vraiment très cool. De plus, il est beaucoup plus facile à lire. C'est aussi beaucoup plus rapide. J'ai réexécuté ma requête d'origine et il a fallu 5:36 et cette requête a pris 1:08. Merci beaucoup! –

+0

Merci pour l'exemple de comparaison. J'ai accepté ceci comme réponse parce que cela a résolu mon problème. Et je pensais que puisque je l'acceptais comme réponse, il serait évident que je suis d'accord, mais je voterai aussi pour cela. J'apprécie votre aide! –