【问题标题】:SQL Statement - How can Improve speed with indexingSQL 语句 - 如何提高索引速度
【发布时间】:2013-03-26 01:56:15
【问题描述】:

我有一个脚本,它必须查看超过 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

如何使用索引使其更快?

【问题讨论】:

  • 嗯,首先,请显示您的表架构,以及任何现有的索引定义。我是 Oracle 人,但 SQL Server 没有工具来显示查询访问计划(如 oracle 中的“解释计划”)?这是我的第一个建议。
  • 不可能从中确定(我们需要解释计划),但我怀疑超过ToMemberId 将是一个好的开始。另外,为什么你有两个“删除”标志?
  • TOP 没有 ORDER BY?所以你不在乎你得到哪一个?
  • 你的表结构是什么?您目前有哪些索引?你看过执行计划吗?

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


【解决方案1】:

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

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;

您可能还想尝试在密钥中使用MemberMailID 而不是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;

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

【讨论】:

    【解决方案2】:

    看起来很适合filtered index

    过滤索引是优化的非聚集索引,特别适合 涵盖从明确定义的数据子集中选择的查询。它 使用过滤谓词来索引表中的部分行。一个 精心设计的过滤索引可以提高查询性能,减少 索引维护成本,降低索引存储成本 全表索引。

    类似的东西:

    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;
    

    【讨论】:

    • 听起来是个好主意! :-) 但是您的版本可能需要查找 MemberMailID...
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-30
        • 1970-01-01
        • 2011-11-13
        • 2020-02-20
        • 2013-03-18
        • 1970-01-01
        • 2016-03-20
        相关资源
        最近更新 更多