大数据集上的Sql语句

时间:2013-01-12 23:57:38

标签: sql sql-server sql-server-2008

我有一个存储过程,它使用逻辑之间的一些数据来恢复数据块。我的语句中的PostFamilyTags表有大约150万行。下面的sql语句运行速度很慢。

SELECT TOP(100)*  FROM
    (SELECT ROW_NUMBER() 
        OVER(ORDER BY p.date  DESC) as NUM,    
        m.postfamilymediaID, 
        m.postfamilyID, 
        p.blogID,
        p.userID, 
        p.BlogPostID, 
        m.postfamilymediatypeID as Type, 
        p.Title, 
        m.Address, 
        m.AddressEncoded, 
        m.ThumbNailAddress, 
        p.Date, 
        p.Summary, 
        p.Url, 
        m.ThumbNailIndex, 
        m.ThumbNailHeight, 
        m.ThumbNailWidth, 
        m.ThumbNailHeightAlt, 
        m.ThumbNailWidthAlt, 
        m.ItemName, 
        m.id3Title, 
        m.id3SubTitle, 
        m.id3ContributingArtists, 
        m.id3AlbumArtist, 
        m.id3Album, 
        m.id3Year, 
        m.id3Genre, 
        m.id3Length, 
        m.IsPublic      
FROM         
        PostFamilyMedia as m
        inner join 
        PostFamily as p on m.postfamilyID = p.postfamilyID 
        inner join 
        PostFamilyTags as pt on p.postfamilyID = pt.postfamilyID 
        inner join --Tags
        Tags as t on pt.tagID = t.tagID 
        Where t.TagLevel = 1 and t.Tag = 'Electronic' 
) AS a  WHERE NUM >= (100 + 1)  AND NUM <= (100 + 100)

但是当我把逻辑推出时,它的效果很好。

SELECT TOP(100)
        m.postfamilymediaID, 
        m.postfamilyID, 
        p.blogID,
        p.userID, 
        p.BlogPostID, 
        m.postfamilymediatypeID as Type, 
        p.Title, 
        m.Address, 
        m.AddressEncoded, 
        m.ThumbNailAddress, 
        p.Date, 
        p.Summary, 
        p.Url, 
        m.ThumbNailIndex, 
        m.ThumbNailHeight, 
        m.ThumbNailWidth, 
        m.ThumbNailHeightAlt, 
        m.ThumbNailWidthAlt, 
        m.ItemName, 
        m.id3Title, 
        m.id3SubTitle, 
        m.id3ContributingArtists, 
        m.id3AlbumArtist, 
        m.id3Album, 
        m.id3Year, 
        m.id3Genre, 
        m.id3Length, 
        m.IsPublic      
FROM         
        PostFamilyMedia as m
        inner join 
        PostFamily as p on m.postfamilyID = p.postfamilyID 
        inner join 
        PostFamilyTags as pt on p.postfamilyID = pt.postfamilyID 
        inner join --Tags
        Tags as t on pt.tagID = t.tagID 
        Where t.TagLevel = 1 and t.Tag = 'Electronic' 

任何人都可以帮助我让我的第一个sql语句运行得更快吗?

3 个答案:

答案 0 :(得分:1)

由于您没有从任何一个标签表中选择任何列,因此您可以采用不同的方式来编写此列:

Select Top(100)
  *
From (
  Select
    Row_Number() Over (Order By p.date Desc) as Num,
    m.postfamilymediaID,
    m.postfamilyID,
    m.postfamilymediatypeID as Type, 
    p.Title, 
    p.Date -- and the rest of the fields
  From
    PostFamilyMedia As m
      Inner Join 
    PostFamily As p On m.postfamilyID = p.postfamilyID 
  Where
    Exists (
      Select 
        'x'
      From 
        Tags As t 
          Inner Join
        PostFamilyTags As pt 
          On pt.tagID = t.tagID 
      Where
        t.TagLevel = 1 and
        t.Tag = 'Electronic' And
        p.postfamilyID = pt.postfamilyID
      )
  ) As a
Where
  Num >= (100 + 1) And Num <= (100 + 100);

http://sqlfiddle.com/#!3/e073d/1的一些非常基本的测试中,以这种方式编写将在日期列上使用覆盖索引,而现在使用它的方式则不然。这是否适用于更大的数量(以及它是否能提高性能)需要进行测试。

另外,我认为PostFamilyTags (PostFamilyID, TagID)是唯一的。这种查询对您定义唯一索引的顺序很敏感。找出最佳选择的最简单方法是创建两者并查看优化器选择的内容。看起来TagID, PostFamilyID最适合小批量使用。

如果Tags (TagLevel, Tag)是唯一的,您可能会在单独的查询中读取唯一的TagID,然后从主查询中删除标记。由于标签相对于其他表格可能较小,我不希望这会产生太大影响。

Declare @TagID int
Select
  @TagID = TagID
From
  Tags
Where
  TagLevel = 1 And
  Tag = 'Electronic'

Select Top(100)
  *
From (
  Select
    Row_Number() Over (Order By p.date Desc) as Num,
    m.postfamilymediaID,
    m.postfamilyID,
    m.postfamilymediatypeID as Type, 
    p.Title, 
    p.Date -- and the rest of the fields...
  From
    PostFamilyMedia As m
      Inner Join 
    PostFamily As p On m.postfamilyID = p.postfamilyID 
  Where
    Exists (
      Select 
        'x'
      From 
        PostFamilyTags As pt 
      Where
        p.postfamilyID = pt.postfamilyID And
        pt.TagID = @TagID
      )
  ) As a
Where
  Num >= (100 + 1) And Num <= (100 + 100);

当您为每个匹配的PostFamilyMedia选择所有PostFamily时,您可以通过将第一个表格集中在PostFamilyID, PostFamilyMediaID而不是其主键来加快速度。包含第二列以使其独特。 SQL Server将向非唯一聚簇索引添加隐藏的uniquifier值。权衡的是,如果您的应用程序的另一部分选择单个记录,它将稍微慢一些。您可以使用另一个覆盖索引来快速获取,但代价是插入和更新速度较慢。

答案 1 :(得分:0)

问题可能是你认为“快”与“慢”的问题。当查询可能返回数百万行时,通常将第一行的时间用作查询的长度。但是,您需要考虑最后一行的时间。

通过添加row_number函数,SQL需要在返回任何行之前生成整个结果集。它看起来更慢,但是当测量到整个结果集的时间时,它并不是真的慢(因为row_number())。

您可以通过在子查询中执行row_number()来加快速度:

from (select row_number() order by pdate) . . .
      from PostFamily p
     )

然后在on子句中包含条件。

明智地使用索引可能有所帮助。你在桌上的索引中有pdate吗?但是,我不确定这会有所帮助。

答案 2 :(得分:0)

直接回答你的问题;我使第一个查询更快的方法是索引table.column(order):**PostFamily.date DESC**

我说这个的原因是看起来你需要分页你的数据(基于[Num])。正如人们所指出的那样,ROW_NUMBER()操作需要读取所有符合条件的行。但是,它们不仅需要阅读,还需要排序。排序非常昂贵,尤其是在大型数据集上。我希望索引正如我所描述的那样有助于此。

为了解释两个查询的不同,我可以提供一个类比。鉴于以下列表:

Mike
Susan
Andrew
Felicity
George
Laura
Ben
Robert
Julia
Jim
Kath
  1. 给我前三名
  2. 按反向字母顺序给我前3名。
  3. 这两项任务中的哪一项会花费你更多的工作?