非常慢的Sql Server查询

时间:2009-10-07 07:15:54

标签: sql-server

我有2个表来自合并以下表:

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

对这些表进行非规范化后,得到的表格为:

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

以下是结果表中数据的条件:

  • SQL Server 2008数据库
  • 两个表之间的关系是物理应用的
  • 作者表有5000万条记录
  • 文章表有2000万条记录
  • 作者在同一年用不同的电子邮件撰写了许多文章
  • 作者表中有作者的ArIds没有在文章表中引用ArIds(孤儿记录)
  • 年份字段中的值范围为2002年和2009年
  • Articles表在[FieldId和Year]字段上有一个唯一的聚簇索引,该索引在9个分区上创建(每年1个分区)
  • Authors表在[Year,ArId,Aid]字段上有一个非唯一聚簇索引,该索引在与Article表相同的9分区上创建(每年1个分区)

问题是:

  • 我们需要创建一个存储过程,在以下条件下从两个表[Aid,Surname,Email]获取以下结果:

  • 在特定年份(AND)期间和之后撰写文章的作者

  • 作者的文章总数大于特定数字(AND)
  • 作者在特定ClassNumber下撰写的文章数量大于其文章总数的特定百分比(AND)
  • 只获取作者的最新电子邮件(在他撰写文章的最后一年)
  • 如果作者在同一年有多封电子邮件,请全部收到。

我们需要查询花费最少的时间

如果有人可以提供帮助,非常感谢。

4 个答案:

答案 0 :(得分:2)

如果没有这些数据,这很难处理,但我创建了表格并复制了程序,以便大致了解查询计划和潜在问题。

第一个值得注意的事情,查询的部分写成:

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

要进行表扫描,您将Year作为分区键,但在每个分区中,没有索引支持查询中的email子句。作为旁注,EAE.Email!=''可能不会给你很满意的期望。     如果''!=''print'true',则打印'false' 这对大多数系统都是错误的。 (基于ansi填充)

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

ED.ClassNumber没有支持索引,导致聚簇索引扫描。

在最终的选择声明中:     INNER JOIN作者EA ON EA.Aid =#TT.Aid

#TT方面没有支持索引,在作者表一侧似乎没有。

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

这没有支持索引,导致扫描。

还有很多问题,有大量的问题可能会随着合适的索引而消失 - 你必须在表格上找出一些基本的索引,然后得到一个新的查询计划/集合问题并反复修复计划 - 你不会在一个'银弹'镜头中修复它。

答案 1 :(得分:1)

您是否需要帮助编写查询,或帮助修复性能?查询本身应该相对简单。这不是你要获得最大收益的地方。

SQL Server通过调整索引自带tools for analyzing queries and boosting performance。这就是你要看到帮助它快速运行的最大帮助。

答案 2 :(得分:0)

第一步是适当的索引。使用where标准作为主要竞争者,然后在未在选址中使用的项目可以简单地包含在索引中。如上所述,有标准工具和查询可以找到这些。

要专注于查询,请运行查询并启用“查询| 包含执行计划”(Ctrl + M)。这应该显示出任何明显的瓶颈。

答案 3 :(得分:0)

考虑到前面提到的条件 这是我创建的查询,但需要3分钟(网页响应的时间很长):

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