2

我有一个脚本,它必须查看超过 250 万条记录,以查找是否有未读电子邮件的成员。我想知道可以做些什么来提高它的速度。目前,运行脚本最多可能需要 8 秒:

SELECT TOP(1) MemberMailID
FROM MemberMail
WHERE ToReadFlag = 0
AND ToMemberID = 102
AND ToDeletedFlag = 0
AND FromDeletedFlag = 0
AND OnHold = 0
AND ToArchivedFlag = 0

如何使用索引使其更快?

4

4 回答 4

4

该索引可能会有所帮助,但请记住,没有免费的午餐(必须维护索引,因此这会影响您的插入/更新/删除工作量):

CREATE NONCLUSTERED INDEX unread_emails
  ON dbo.MemberMail(ToMemberID)
  INCLUDE (MemberMailID)
  WHERE ToReadFlag = 0
  AND ToDeletedFlag = 0
  AND FromDeletedFlag = 0
  AND OnHold = 0
  AND ToArchivedFlag = 0;

现在您的查询可以说:

SELECT TOP (1) MemberMailID
  FROM dbo.MemberMail -- dbo prefix
    WITH (INDEX (unread_emails)) -- in case you need to force, though you should not
WHERE ToMemberID = 102
AND ToReadFlag = 0
AND ToDeletedFlag = 0
AND FromDeletedFlag = 0
AND OnHold = 0
AND ToArchivedFlag = 0
ORDER BY ToMemberID; -- ORDER BY is important!

如果您根据查询更改其中一些标志的值,您可以尝试将这些列添加到索引的键而不是过滤器,例如,假设有时您检查OnHold = 0并且有时OnHold = 1

CREATE NONCLUSTERED INDEX unread_emails
  ON dbo.MemberMail(ToMemberID, OnHold)
  INCLUDE (MemberMailID)
  WHERE ToReadFlag = 0
  AND ToDeletedFlag = 0
  AND FromDeletedFlag = 0
  AND ToArchivedFlag = 0;

您可能还想尝试使用MemberMailIDin 代替INCLUDE. 例如:

CREATE NONCLUSTERED INDEX unread_emails
  ON dbo.MemberMail(ToMemberID, MemberMailID)
  WHERE ToReadFlag = 0
  AND ToDeletedFlag = 0
  AND FromDeletedFlag = 0
  AND OnHold = 0
  AND ToArchivedFlag = 0;

这些差异可能对您的数据和使用模式无关紧要,但您将能够比我们猜测的更容易测试差异。

于 2013-03-25T17:51:14.160 回答
3

看起来很适合过滤索引

过滤索引是一种优化的非聚集索引,特别适用于覆盖从明确定义的数据子集中进行选择的查询。它使用过滤谓词来索引表中的部分行。与全表索引相比,设计良好的过滤索引可以提高查询性能,降低索引维护成本,降低索引存储成本。

这些方面的东西:

CREATE NONCLUSTERED INDEX IX_MemberMail_ToMemberId_Unread
ON dbo.MemberMail (ToMemberId ASC)
WHERE ToReadFlag = 0
AND ToDeletedFlag = 0
AND FromDeletedFlag = 0
AND OnHold = 0
AND ToArchivedFlag = 0;
于 2013-03-25T17:56:09.633 回答
2

在 SSMS 中通过 (CTRL+M)获取实际查询计划。或者将您的查询粘贴到 SSMS 中,右键单击它,选择在数据库引擎优化顾问中分析查询,您将看到需要添加的索引。基本上,您需要一个复合+包含索引。

于 2013-03-25T17:36:42.653 回答
0

作为一个经验法则,您执行频繁过滤器(条件)的每个where字段都必须被索引。

同样,作为一个经验法则,我遵循以下标准:

  1. 每个关键字段(主字段或外字段)都必须编入索引
  2. date我必须执行频繁查找的每个字段都必须被索引
  3. 尽管我避免了它,但如果我需要对charvarchar字段执行频繁的搜索,我也会对它们进行索引

请注意,很容易陷入索引所有内容的诱惑。不要这样做。小心并以最佳的成本效益关系设计您的索引。

我是 MySQL 用户,我不知道如何在 SQL Server 中执行此操作,但必须有一种方法可以显示查询的执行计划(在 MySQL 中是explain select...)。尝试显示执行计划,然后在此基础上决定您需要索引哪些字段。

于 2013-03-25T17:37:16.660 回答