2009-07-09 4 views
0

J'ai une application en cours d'exécution sur mon SQL Server qui commence à ralentir sur une tâche spécifique. J'ai couru le profileur de SQL et ai noté que la requête suivante de prend énormément de temps (1-2 minutes). Je n'ai pas accès au code pour changer la requête.
Y at-il quelque chose que je peux syntoniser/modifier dans la base de données? Le tableau PC10000 dans la déclaration ci-dessous a env. 119000 enregistrements. J'ai aussi le plan d'exécution ci-joint.Tune Slow SQL Query

SELECT TOP 25 
    zProjectID, zTaskID, zTransactionNumber, zTransactionDate, zUserID, 
    zCostCategoryDDL, zCostCategoryString, zSubCostCategory, zSubCostCategoryString, 
    zDepartmentID, zJournalEntry, zPostingDate, zSalesPostingDate, zPeriodNumber, 
    zTransactionDescription, zBillingDescriptionLine1, zBillingDescriptionLine2, 
    zBillingDescriptionLine3, zBillingDescriptionLine4, zSalesAccountIndex, 
    zSalesAccountString, zDistDocumentTypeDDL, zDistDocumentNumber, zDistSequenceNumber, 
    zSalesDocumentTypeDDL, zSalesDocumentNumber, zSalesLineNumber, zDistHistoryYear, 
    zSeriesDDL, zSourceDoc, zWebSource, zOrigDocumentNumber, zOrigDocumentDate, 
    zOrigID, zOrigName, zExpenseStatusDDL, zApprovalUserIDCost, zAccountIndex, 
    zAccountNumberString, zBillingStatusDDL, zApprovalUserIDBilling, zBillingWorkQty, 
    zBillingWorkAmt, zQty, zQtyBilled, zUnitCost, 
    zUnitPrice, zRevenueAmt, zOriginatingRevenueAmt, zCostAmtEntered, zCostAmt, 
    zOriginatingCostAmt, zPayGroupID, zPayrollStatusDDL, zTotalTimeStatusDDL, 
    zEmployeeID, zHoursEntered, zHoursPaid, zPayRecord, zItemID, zItemDescription, 
    zUofM, zItemQty, zBurdenStatusDDL, zUserDefinedDate, zUserDefinedDate2, 
    zUserDefinedString, zUserDefinedString2, zUserDefinedCurrency, 
    zUserDefinedCurrency2, zNoteIndex, zImportType, DEX_ROW_ID 
FROM 
    DBServer.dbo.pc10000 
WHERE 
    (zDistDocumentNumber in 
     (select cast(JRNENTRY as varchar(20)) 
      from DBServer..GL10001 
      where BACHNUMB = 'PMCHK00004283') 
    or zSalesDocumentNumber in 
     (select cast(JRNENTRY as varchar(20)) 
      from DBServer..GL10001 
      where BACHNUMB = 'PMCHK00004283')) 
ORDER BY 
    zProjectID ASC ,zTaskID ASC ,zTransactionNumber ASC 

alt text

+0

Pouvez-vous rendre le fait que vous n'avez pas accès au code plus explicite dans la question, c'est-à-dire en gras. – pjp

+1

Edité pour souligner le fait qu'il ne peut pas changer la question. –

+0

Pourquoi le code ne peut-il pas être modifié. La requête est-elle exécutée via un processus stocké? – pjp

Répondre

6

Le plus gros problème que vous avez semble être dû au manque d'index appropriés. Vous pouvez le voir en raison de la présence d'analyses de table dans le plan d'exécution.

Les scans de table atteignent les performances car ils signifient que toute la table est analysée pour rechercher des données correspondant aux clauses données dans la requête.

Je vous recommande d'ajouter un index sur BACHNUMB dans GL10001

Vous pouvez également essayer des index sur zDistDocumentNumber et zSalesDocumentNumber en PC10000, mais je pense que l'indice de GL10001 est le principal. Les clauses "IN" sont généralement assez coûteuses par rapport aux autres techniques, mais comme vous ne pouvez pas changer la requête elle-même, vous ne pouvez rien y faire.

Sans aucun doute, vous avez besoin d'ajouter des index appropriés

3

La requête est en train de faire 2 scans de table sur la table GL10001. D'un coup d'œil à la requête (qui est un peu difficile à lire) je verrais si vous avez un index sur la colonne BACHNUMB.

+1

Comme ces deux sous-requêtes prennent chacune (selon le plan d'exécution) 47% du temps global, diable ouais les indexer. Quelle est la taille de la table GL10001? –

0

Vous pouvez réécrire les sous-requêtes comme une jointure, et ajouter un index à GP01..GL10001 sur BACHNUMB et JRNENTRY

+1

Malheureusement, il mentionne qu'il ne peut pas changer la requête. –

+0

@Justin Niessner: l'ajout d'un index ne change pas la requête. S'il veut le maximum de performance, alors ces sous-critères devraient être une jointure –

0

Puisque vous ne pouvez pas changer la requête, la meilleure chose que vous puissiez faire est de vous assurer vous avez des index sur les colonnes que vous utilisez pour vos jointures (et sous-requêtes). Si vous pensez à un meilleur plan de requête, vous pouvez le fournir à SQL Server au lieu de le laisser calculer le sien (c'est un cas très rare).

1

le plan d'exécution montre assez clairement que la localisation en fait les lignes est ce qui prend tout le temps (pas lookups de signet encombrants, ou l'agrégation/réorganiser les tâches), il est donc très positivement une question d'indexation. survolez les analyses de table dans le plan d'exécution et cochez 'objet' dans l'info-bulle, pour voir quelles colonnes sont utilisées. voir à ce qu'ils sont indexés. Vous pouvez également exécuter une trace pour échantillonner certaines données en direct et les transmettre au conseiller d'optimisation de la base de données.

0

Remplacer le OU avec une UNION ALL de deux requêtes cela devrait se faire tirer dessus de ces bobines

-à-dire exécuter la requête une fois avec quelque chose comme ça

SELECT .... 

(zDistDocumentNumber in 
    (select cast(JRNENTRY as varchar(20)) 
     from DBServer..GL10001 
     where BACHNUMB = 'PMCHK00004283') 

UNION ALL 

SELECT ... 

zSalesDocumentNumber in 
    (select cast(JRNENTRY as varchar(20)) 
     from DBServer..GL10001 
     where BACHNUMB = 'PMCHK00004283')) 
+0

ypu me battre! Je suis d'accord avec pjp ... ajouter aussi les index. –

+0

ressemble à une application de comptabilité, l'ajout d'index peut également affecter d'autres requêtes ... gardez cela en considération. –

0

En plus d'ajouter des index , vous pouvez également convertir les instructions IN en EXISTS ...Quelque chose de ce genre:

SELECT TOP 25 .... 
FROM GP01.dbo.pc10000 parent 
WHERE EXISTS 
    (
    SELECT child.* 
    FROM GP01..GL10001 child 
    WHERE BACHNUMB = 'PMCHK00004283' 
     and parent.zDistDocumentNumber = child.JRNENTRY 
    ) 
    OR EXISTS 
    (
    SELECT child2.* 
    FROM GP01..GL10001 child2 
    WHERE BACHNUMB = 'PMCHK00004283' 
     and parent.zSalesDocumentnumber = child2.JRENTRY 
    ) 
ORDER BY zProjectID ASC ,zTaskID ASC ,zTransactionNumber ASC