【问题标题】:Indexing for complex predicates复杂谓词的索引
【发布时间】:2020-10-23 23:17:37
【问题描述】:

我正在努力确定有效的索引(或重写查询)以改进具有以下混淆谓词的查询:

  • 在一个范围内的一个表的日期上加入 - 在第二个表的两个日期字段之间(一个可以为空,一个在 PK 中不能为空)。
  • 使用的日期实际上是日期字段中的值(可为空)+1。
  • WHERE 子句在多个标志字段上包含 OR 逻辑。

查询的简化版本是:

select
d.dim_date_id
,f.dim_provider_id
,f.dim_event_id
,d.date

from DWH.dbo.tbl_fact_outcome f
join   DWH.dbo.tbl_dim_date d on DATEADD(DAY,1,d.date) between f.known_from and f.known_to 

where
f.known_from > getdate()-12
and (d.flag_latest_day = 'Y' or  d.flag_end_of_month = 'Y'  or (d.flag_end_of_week = 'Y' AND d.flag_latest_week = 'Y'))
and d.flag_future_day = 'N'
and f.deleted = 0

tbl_fact_outcome 有这些索引:

  • input_form_id 上的 PK 聚簇索引,known_from
  • deleted、known_from、known_to 上的非唯一非聚集索引(包括所需的 _dim_id 字段)

tbl_dim_date 有这些索引:

  • dim_date_id 上的 PK 聚簇索引
  • flag_future_day 上的非唯一非聚集索引,日期(包括相关标志字段)

目前,它估计有 853 行,但返回 16,784。

这是查询计划: https://www.brentozar.com/pastetheplan/?id=rydKb_3AI

统计数据是最新的。 我尝试重新排序覆盖索引,但没有任何改进。

我完全不知道还有什么可以尝试使用索引或代码本身来提高性能,所以任何指针都值得赞赏。


编辑 05/07/2020

这里排除了以下建议:

  • tbl_fact_outcome 上的过滤索引(删除时) - 不到 1% 的记录将被过滤掉,因此不值得
  • tbl_dim_date 上的过滤索引(使用查询中的整个 WHERE 子句) - 无法在索引中使用 OR
  • tbl_dim_date 上的索引,包含字段作为关键字段 - 尝试过这个,没有任何区别,优化器没有使用。

【问题讨论】:

  • 您的索引是否有过滤条件或者它们是未过滤的索引?
  • 它们是未过滤的
  • d.flag_future_day是什么意思?我对此有不好的预感。
  • SMor - 该表是日期列表,字段 flag_future_day 是一个 Y/N 标志,用于标识未来的日期。

标签: sql-server optimization indexing query-tuning


【解决方案1】:

猜测deleted 上的所有/大多数查询过滤器我建议使用过滤索引。

CREATE NONCLUSTERED INDEX TodoNewIndexName ON DWH.dbo.tbl_fact_outcome (
    known_from ASC
    ,known_to ASC
    )
INCLUDE (dim_event_id,dim_provider_id)
WHERE deleted = 0;

如果此查询确实经常运行,您还可以考虑为tbl_dim_date 使用过滤索引。这可能只会被此查询使用,因为 where 与您的查询完全匹配:

CREATE NONCLUSTERED INDEX TodoNewIndexName ON DWH.dbo.tbl_dim_date (DATE ASC)
    WHERE (
            d.flag_latest_day = 'Y'
            OR d.flag_end_of_month = 'Y'
            OR (
                d.flag_end_of_week = 'Y'
                AND d.flag_latest_week = 'Y'
                )
            )
        AND d.flag_future_day = 'N'

如果您不希望标志字段上的过滤索引。您应该将标志字段添加到索引而不是包含。

 CREATE NONCLUSTERED INDEX TodoNewIndexName ON DWH.dbo.tbl_dim_date (
    DATE ASC
    ,flag_latest_day ASC
    ,flag_end_of_month ASC
    ,flag_end_of_week ASC
    ,flag_latest_week ASC
    ) 

这应该做的是摆脱关于急切假脱机的Index Spool (Eager Spool)more info

急切的索引假脱机通常表明有用的永久索引已 数据库模式中缺少。情况并非总是如此,因为 流式表值函数示例展示。

【讨论】:

  • 感谢您的回复。重新过滤 tbl_fact_outcome 上的索引 - 不到 1% 的记录被标记为已删除,所以在这种情况下,我认为这不会有帮助。 tbl_dim_date 上的过滤索引是不可能的,因为 SQL Server 不允许过滤器中的 OR 条件(SQL Server 2014 至少不允许)。我在 tbl_dim_date 上尝试了您的最终索引,但优化器坚持使用现有索引(将这些字段作为 INCLUDE)并且仍然具有急切的假脱机。
【解决方案2】:

您的日期维度是否包含 nextDay 列或其他内容?如果没有,您可以添加此列并将 DATEADD(DAY,1,d.date) 替换为此新列。

【讨论】:

  • 目前没有,但如果我不能通过索引或查询调优解决这个问题,则需要考虑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-20
  • 1970-01-01
相关资源
最近更新 更多