2009-10-07 4 views
0

J'ai 2 tables ont permis de fusionner les tableaux suivants:Très lent requêtes SQL Server

Authors 
-Aid bigint 
-Surname nvarchar(500) 
-Email nvarchar(500) 

Articles 
-ArId varchar(50) 
-Year int 
-……Some other fields…… 

ArticleAuthors 
-ArId varchar(50) 
-Aid bigint 

Classifications 
-ClassNumber int 
-ClassDescription nvarchar(100) 

ClassArticles 
-ArId varchar(50) 
-ClassNumber int 

Après dénormaliser ces tables les tables abouti étaient:

Articles 
-FieldId int 
-ArId varchar(50) 
-ClassNumber int (Foreign key from the Classifications table) 
-Year int 

Authors 
-FieldId int 
-ArId varchar(50) (Foreign key from the Articles table) 
-Aid bigint 
-Surname nvarchar(500) 
-Email nvarchar(500) 
-Year int 

Voici les conditions des données à l'intérieur les tables: pour résultat

  • base de données SQL Server 2008
  • Les relations entre les deux tables sont appliquées physiquement
  • La table authors a 50 millions de disques
  • Le tableau des articles a 20 millions de disques
  • L'auteur a écrit de nombreux articles au cours de la même année avec des e-mails différents
  • Il sont les auteurs dans la table des auteurs avec ArIds qui ne référencent pas ArIds dans la table Articles (enregistrements orphelins)
  • Les valeurs dans les champs Année s'étendent de 2002 à 2009
  • La table Articles a un index cluster unique sur la [ FieldId et Yea r] fields et cet index créé sur 9 partitions (1 partition par an)
  • La table Authors a un index cluster non unique dans les champs [Year, ArId, Aid] et cet index est créé sur la même partition que la table des articles (1 partition par an)

la question est:

  • Nous devons créer une procédure stockée qui obtient le résultat suivant des deux tables [aide, prénom, adresse électronique] sous les conditions suivantes:

  • Les auteurs qui ont écrit des articles pendant et après une année donnée (ET)

  • Le nombre total d'articles pour l'auteur est supérieur à un nombre spécifique (ET)
  • Le nombre des articles écrits par l'auteur sous spécifique ClassNumber est supérieur à un pourcentage spécifique du nombre total de ses articles (AND)
  • Recevez seulement l'email le plus récent de l'auteur (dans la dernière année au cours de laquelle il a écrit un article)
  • Si l'auteur a plus d'un courriel la même année, obtenez-les tous.

Nous avons besoin de la requête pour prendre le moins de temps possible

Si quelqu'un peut aider, Merci beaucoup.

Répondre

2

Sans avoir les données ce qui est très difficile de travailler , mais j'ai créé les tables et dupliqué la procédure pour obtenir une idée approximative sur le plan de requête et les problèmes potentiels.

La première chose notable, la partie de la requête écrite comme:

SELECT DISTINCT Aid 
FROM Authors EAE 
WHERE EAE.[Year] >= @year AND EAE.Email IS NOT NULL AND EAE.Email != ' ' 

va scan de table, vous avez année comme la clé de répartition, mais dans chaque partition il n'y a pas d'index soutenir les clauses de courrier électronique dans la requête. En remarque, EAE.Email! = '' Pourrait ne pas vous donner tout à fait ce que vous attendez. Si ''! = '' Imprimer 'vrai' sinon imprimer 'faux' Cela donnera faux pour la plupart des systèmes. (Basé sur ansi padding)

FROM Articles ED 
INNER JOIN Authors EAD ON EAD.ArId = ED.ArId 
WHERE EAD.Aid = [YearAuthors].Aid AND ED.ClassNumber = @classNumber 

ED.ClassNumber aura pas d'index de soutien, ce qui provoque un balayage d'index ordonné en clusters.

Dans l'instruction select final: INNER JOIN Auteurs EA ON EA.Aid = # TT.Aid

Cela n'a pas d'indice d'appui sur le côté #TT et ne semble pas être un sur la table des auteurs côté.

WHERE EA.Email IS NOT NULL AND EA.Email != ' ' 

Ceci n'a aucun index de support, causant un balayage.

Il y a beaucoup plus de problèmes là-dedans, avec un nombre considérable de tri apparaissant qui disparaîtront probablement avec des index appropriés - Vous devrez trier une partie de l'indexation de base sur les tables et ensuite obtenir un nouveau plan de requête/ensemble de problèmes et itérativement réparer le plan - vous ne le résoudrez pas dans une seule balle "balle d'argent".

0

La première étape serait les index appropriés. Avec les critères où les candidats sont les principaux prétendants, puis les éléments non utilisés dans où, mais sélectionnés peuvent simplement être inclus dans l'indice. Comme mentionné, il existe des outils standard et des requêtes pour les trouver.

Pour vous concentrer sur la requête en cours, lancez la requête avec "Requête | Inclure le plan d'exécution" (Ctrl + M) activé.Cela devrait montrer tout goulot d'étranglement évident.

+0

selon les recommandations du conseiller Tuning j'ai créé les indices suivants: * sur la table Auteurs - [Aide, Arid] - [Aide, Année] - [Aide] * Sur la table des articles: -ClassNumber -ClassNumberYear –

+0

@Darsh mise à jour la réponse. Si cela ne vous aide pas, vous pouvez inclure une requête réelle en question. – dove

1

Souhaitez-vous de l'aide pour rédiger la requête ou pour aider à corriger la performance? La requête elle-même devrait être relativement simple. Ce n'est pas là que vous allez obtenir le plus pour votre argent.

SQL Server est livré avec tools for analyzing queries and boosting performance en ajustant vos index. C'est là que vous allez voir la plus grande aide pour l'exécuter rapidement.

+0

Mon problème est la performance et comme je le mentionne dans le commentaire sur la première réponse, la meilleure optimisation que j'ai faite prend 3 minutes. –

0

Compte tenu des conditions précitées dans Ceci est la requête que je l'ai créé, mais il faut 3 minutes (donc temps pour une réponse de page Web):

CREATE PROC [dbo].[GetAuthorForMailing] 
(
    @classNumber INT, 
    @noPapers int, 
    @year int, 
    @percent int 
) 
AS 
BEGIN 

CREATE TABLE #TT 
(
    Aid bigint, 
    allPapers int, 
    classPapers int,  
    perc as CEILING(CAST(classPapers AS DECIMAL)/CAST(allPapers AS DECIMAL) * 100) 
) 
INSERT INTO #TT(Aid,allPapers,classPapers) 
SELECT [YearAuthors].Aid, 
      (
      SELECT COUNT(EA.Aid) 
      FROM Authors EA 
      WHERE EA.Aid =[YearAuthors].Aid) AS [AllPapers], 
      (
      SELECT COUNT(*) 
      FROM Articles ED INNER JOIN Authors EAD ON EAD.ArId = ED.ArId 
      WHERE EAD.Aid = [YearAuthors].Aid AND ED.ClassNumber = @classNumber) AS [ClassPapers] 

FROM 
(
     SELECT DISTINCT Aid 
     FROM Authors EAE 
     WHERE EAE.[Year] >= @year AND EAE.Email IS NOT NULL AND EAE.Email != ' ' 

)AS [YearAuthors] 

SELECT DISTINCT EA.Aid,EA.Surname,EA.Email,[Year] 
FROM #TT INNER JOIN Authors EA ON EA.Aid = #TT.Aid 
    AND allPapers > @noPapers 
    AND perc > @percent 
    AND EA.[Year] = (SELECT MAX([Year]) FROM Authors WHERE Aid = EA.Aid) 
WHERE EA.Email IS NOT NULL AND EA.Email != ' ' 
DROP TABLE #TT 
Questions connexes