【问题标题】:tsql query and index questiontsql查询和索引问题
【发布时间】:2011-03-20 08:28:13
【问题描述】:

我有一张以 id 作为主键存储照片信息的表:

id(PK)、title、album_id、posted_by、 已发布、文件名、标签、评级、 发布日期

此表将保存 100+ 百万张照片和 我需要经常像这样运行这个查询:

1) 获取给定相册的所有照片(仅 id、文件名、标题列)

从照片中选择 ID、文件名、标题 其中 album_id = @AlbumId 和 已发布 = 1

2) 获取给定用户的所有已发布照片,但不包括当前查看相册的照片

从照片中选择 ID、文件名、标题 其中posted_by='bob'和album_id 10 和已发布 = 1

我想避免索引和表扫描。我需要尽可能多地使用 seek(比如 100%)。

这可以吗? 什么类型的索引以及在哪些列上可以帮助我实现这一目标?

谢谢

【问题讨论】:

  • Published 列的基数是多少? (也就是说,它可能包含哪些不同的值以及每个值有多少?)
  • AlbumId 和 posted_by 同上:对于每一列,可能有多少不同的值,以及任何给定值的行数?
  • published 是一个位类型的列:所以 1 或 0 AlbumId:会变得相当大,比如从 1 到 10M 的 1000 万张贴_by 是 varchar(20),所以我可以容纳非常大的用户

标签: sql indexing non-clustered-index


【解决方案1】:

实际上,您只能通过在调整之前测量性能自己来发现这一点,然后调整,一次又一次地测量。

但根据您的查询,您应该考虑(或至少先尝试一下)这样的非聚集索引:

CREATE NONCLUSTERED INDEX IX01_Photos
  ON dbo.Photos(album_id, published, posted_by)
  INCLUDE(id, filename, title)

推理:

  • 您最频繁的两个查询都有使用 album_idpublished 的 WHERE 子句 - 所以首先在索引中使用这两列
  • 您的第二个查询还在 WHERE 子句中包含 posted_by - 将其放入与第三列相同的索引中
  • 为了避免对实际数据表进行昂贵的书签查找,您可以在索引中包含 id, filename, title

有了所有这些东西,您应该看到主要是在新的非聚集索引上进行索引搜索以满足您的查询。但再说一遍:许多其他因素也会发挥作用,您可能在问题中没有提到,甚至可能没有考虑过自己 - 但这种方法应该给您一个很好的起点。

【讨论】:

  • 马克,我喜欢你的方法和推理!还有几个问题:标题是唯一可由用户更改的列。这将如何影响您提议的非聚集索引?我有另一列存储查看次数(多少次)照片被查看。每当有人看到照片时,此列就会增加 1。你认为我最好不要在索引中包含那个 colm 吗?
  • 用户是否可以更改“标题”并不重要。显然,如果 Title 列发生变化,则需要更新索引。视图计数:如果您需要在查询中使用它,则显示它 - 是的,然后将其放入 INCLUDE() 列的列表中。如果您不这样做,那么如果您搜索一组照片,并且还想显示查看次数,SQL Server 必须从索引(找到匹配条件的位置)到实际数据页面检索每次点击的观看次数。那些“书签查找”往往既昂贵又缓慢。
【解决方案2】:

您没有提到是否需要在查询中使用 date_posted 或 id 作为过滤条件,因此最好在非按时间顺序的列上使用 CLUSTERED 索引(我假设当前CLUSTERED 索引是 PK。对吗?)。

我会在 album_id 上创建一个 CLUSTERED 索引。

如果您无法更改 CLUSTERED 索引,或者有许多其他查询受益于现有的聚集索引,那么我支持 @marc_s 的答案(并将相应地投票。)

【讨论】:

  • date_posted 和 id col 不会用于过滤。我已经在 id 列上有一个聚集索引
【解决方案3】:

我建议在album_id 上建立一个聚集索引,在posted_by 上建立一个二级索引,如果前者是最受打击的索引。如果posted_by 被击中最多,则反转它们。根据每个album_idposted_by 有多少张照片,在调用代码中过滤published 可能是非常可行的(换句话说,不要将其添加为查询中的限制,而是过滤客户端)。如果没有,您必须将发布的约束添加到查询中,但album_id 的主要限制应该意味着只对published 进行小扫描。但如前所述,在published 客户端进行过滤可能更容易。

【讨论】:

    【解决方案4】:

    ID 上的主键。使其非集群。我猜这不会被太多使用(特别是如果所有查找都是通过专辑或海报进行的)。

    AlbumId 上的聚集索引。似乎它会在大多数查询中使用。

    Posted_By 上的非聚集索引。使用 AlbumId 作为聚集索引,它将出现在该索引的叶级,因此非常类似于 INCLUDEd 列。根据使用情况,将它作为聚集索引可能会更好......但作为 varchar(20),它会占用更多磁盘空间,并且性能会比 AlbumId 更差(假设 AlbumId 是 int)。

    您不能将 Published 作为索引中的列,因为您不能对位列进行索引。你也不想——如果 100M+ 行中只有两个可能的值,SQL 可能永远不会使用它来优化查询。

    我建议对 Posted_By 进行规范化(将其移动到自己的表中,为其提供自己的代理键,并将其用作该表中的外键)。这将显着减少主表中的存储空间,提高整体性能,并允许您在需要时将聚集索引翻转到该列。 (另外,如果“Bob”在桌子上发帖,然后镇上的“Bob”也发帖,你怎么区分 Bob 和 Bob?)

    【讨论】:

    • bob 被用作占位符。该应用不允许重复的用户名。
    • 如果 Posted_By 是唯一列,则使其成为唯一的非聚集索引。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多