1

我有一个存储照片信息的表,其中 id 作为主键:

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

该表将保存 100+ 百万张照片的信息,我需要经常运行这样的查询:

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

从照片中选择 id、文件名、标题,其中 album_id = @AlbumId 并且已发布 = 1

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

从posted_by='bob' 和album_id <>10 和published = 1 的照片中选择ID、文件名、标题

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

这可以做到吗?什么类型的索引和哪些列可以帮助我实现这一目标?

谢谢

4

4 回答 4

2

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

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

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

推理:

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

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

于 2010-07-23T21:47:34.813 回答
0

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

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

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

于 2010-07-23T21:52:56.753 回答
0

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

于 2010-07-23T22:04:12.140 回答
0

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

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

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

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

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

于 2010-07-23T22:21:12.410 回答