【问题标题】:Best Index for query with window functions使用窗口函数查询的最佳索引
【发布时间】:2019-02-20 00:46:18
【问题描述】:

我在 SQL Server 2012 中的查询存在一些性能问题。

该查询用于在表中插入数据,使用窗口函数以不同方式聚合销售数据(上个月、上一年月、周期至今、YTD、MAT)。

在对 Windows 函数进行了相当广泛的研究之后,我认为在从中读取数据的表中建立一个适当的索引会有很大帮助,但我很难找到正确的索引(涉及的列太多)......

表从中读取数据的源表有大约 5000 万行,并且每天都会被 SSIS 包截断和重新加载,可以修改该包以在每次执行中删除和创建索引。

有人可以建议什么索引可能起作用(如果有的话)或任何其他性能改进方法吗?

select语句如下:

SELECT 
    PERIOD,
    CUENTA_ID,
    PROD_ID,
    TIPO_VENTA,
    VENTA_EUROS,
    CICLO,
    DELEGADO_B2B,

    SUM(VENTA_EUROS)                OVER (PARTITION BY CUENTA_ID, PROD_ID, TIPO_VENTA,DELEGADO_B2B              ORDER BY PERIOD ROWS BETWEEN 12 PRECEDING AND 12 PRECEDING) AS VENTA_EUROS_PREV,
    SUM(VENTA_EUROS)                OVER (PARTITION BY CUENTA_ID, PROD_ID, TIPO_VENTA,DELEGADO_B2B,YEAR         ORDER BY PERIOD ROWS UNBOUNDED PRECEDING) AS VENTA_EUROS_YTD,
    SUM(VENTA_EUROS)                OVER (PARTITION BY CUENTA_ID, PROD_ID, TIPO_VENTA,DELEGADO_B2B,YEAR, CICLO  ORDER BY PERIOD ROWS UNBOUNDED PRECEDING) AS VENTA_EUROS_CTD,
    SUM(VENTA_EUROS)                OVER (PARTITION BY CUENTA_ID, PROD_ID, TIPO_VENTA,DELEGADO_B2B              ORDER BY PERIOD ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS VENTA_EUROS_MONTH_PREV,
    SUM(VENTA_EUROS)                OVER (PARTITION BY CUENTA_ID, PROD_ID, TIPO_VENTA,DELEGADO_B2B              ORDER BY PERIOD ROWS 11 PRECEDING) AS VENTA_EUROS_MAT

FROM _REPORTING.[dbo].[RPT_VENTA_MENSUAL_STEP_1]
WHERE YEAR>=YEAR(DATEADD(day,-1,GETDATE()))-1

我检查了执行计划,占最大百分比的部分是三个不同“OVER(PARTITION BY)”的三个排序

计划如下: https://www.brentozar.com/pastetheplan/?id=B1fsgwjBE

感谢和问候

【问题讨论】:

  • 如果您将查询的execution plan 添加到您的问题中会很有帮助。还有你的表结构。
  • @JorgeCampos 我用我从执行计划中得到的信息编辑了帖子,谢谢你的帮助!
  • 请参阅paste the plan 了解在您的问题中包含执行计划的更好方法。
  • 感谢@HABO,我编辑了带有查询计划链接的帖子
  • 我不知道窗口函数中的ORDER BY,但是对于普通ORDER BY,最大的速度提升是在该列上创建聚集索引

标签: sql sql-server tsql


【解决方案1】:

索引需要解决的第一件事是WHERE 子句。不幸的是,它有一个不等式,这使得优化器几乎无法帮助处理窗口子句。

如果你有:

WHERE YEAR = YEAR(DATEADD(day, -1, GETDATE())) - 1

然后优化器可以利用(YEAR, CUENTA_ID, PROD_ID, TIPO_VENTA, DELEGADO_B2B, PERIOD)上的索引。

【讨论】:

  • 谢谢 Gordon,如果我将 WHERE 子句更改为:WHERE YEAR = YEAR(DATEADD(day, -1, GETDATE())) - 1 OR WHERE YEAR = YEAR(DATEADD(day, -1, GETDATE())) (因为我只需要当前和上一年)会有帮助吗?
  • @LuisGarcia-Moreno。 . . OR 是索引杀手。尝试只用一年的时间跑步。如果可行,您可以使用UNION ALL 构造查询。
  • 谢谢!我可以完全删除 where,因为现在源表已经包含当前和上一年
猜你喜欢
  • 1970-01-01
  • 2021-12-09
  • 2019-02-12
  • 1970-01-01
  • 2014-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-20
相关资源
最近更新 更多