Gee*_*zer 8 sql-server optimization execution-plan azure-sql-database query-performance
Azure SQL 数据库。
我有一个表,我需要从中获取Col1
和Col2
基于 的第一行和最新行CreateDate
。
CREATE TABLE dbo.table1 (
Id INT IDENTITY(1,1) PRIMARY KEY ,
Col1 VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL ,
Col2 VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL ,
CreateDate DATETIME NOT NULL
) ;
Run Code Online (Sandbox Code Playgroud)
我有一个像这样的索引:
CREATE INDEX IX__table1_ASC
ON dbo.table1 (Col1, Col2, CreateDate );
Run Code Online (Sandbox Code Playgroud)
我获取第一行的查询是(计划在这里):
--Get the first row
SELECT TOP (1) WITH TIES
*
FROM table1
ORDER BY ROW_NUMBER()
OVER (PARTITION BY Col1, Col2
ORDER BY CreateDate );
Run Code Online (Sandbox Code Playgroud)
索引扫描使用我创建的索引 ( IX__table1_ASC
),但为什么我得到了排序?
我的查询获取最新行(计划在这里):
--get latest row
SELECT TOP (1) WITH TIES
*
FROM table1
ORDER BY ROW_NUMBER()
OVER (PARTITION BY Col1, Col2
ORDER BY CreateDate DESC); --desc here
Run Code Online (Sandbox Code Playgroud)
同样,索引扫描使用索引 ( IX__table1_ASC
),但这次我得到两种排序。索引扫描后的第一个。难道优化器不够聪明,能够以相反的顺序读取索引吗?再说一遍,第二种是做什么用的?
实际的表相当大,因此您可以想象排序的成本很高。我怎样才能最好地优化这里?
Mar*_*ith 17
索引扫描使用我创建的索引 (IX__table1_ASC),但为什么我得到排序?
因为您使用的是一种低效的方式来选择每组的顶行。
只需使用
WITH T
AS (SELECT *,
ROW_NUMBER()
OVER (
PARTITION BY Col1, Col2
ORDER BY CreateDate ) AS RN
FROM table1)
SELECT *
FROM T
WHERE RN = 1
Run Code Online (Sandbox Code Playgroud)
这里TOP (1) WITH TIES
只是一种更加混乱且效率较低的选择行号等于 1 的所有行的方法。不幸的是,StackOverflow 上的一些回答者使用这种方法没有什么充分的理由,我可以看出除了喜欢新奇之外。
在您的第一个执行计划中,排序不是用来计算行号的,而是在没有排序的情况下计算出行编号的结果后对行进行排序的。
关于您的第二个查询,这是一个长期存在的优化器限制 - 您可以获得向后排序的索引扫描,并且不进行排序,如下所示。
WITH T
AS (SELECT *,
ROW_NUMBER()
OVER (
PARTITION BY Col1, Col2
ORDER BY CreateDate DESC ) AS RN
FROM table1
ORDER BY Col1 DESC, Col2 DESC, CreateDate DESC
OFFSET 0 ROWS
)
SELECT *
FROM T
WHERE RN = 1
Run Code Online (Sandbox Code Playgroud)
这OFFSET 0 ROWS
是一种允许ORDER BY
在派生表中使用的 hack,这在 SQL Server 中通常是不允许的。重要的是给优化器一个单独的理由来考虑最佳排序。
演示级别ORDER BY
可以达到相同的目的,但我更喜欢将 hack 放在更接近需要它的地方。此方法还允许您指定不同的呈现顺序。请记住,OFFSET 0
有一天可能会被优化掉,就像TOP (100) PERCENT
现在一样。
在 SQL Server 2000 中,有些人过去通过添加TOP 100 PERCENT ... ORDER BY
. 至少在大多数情况下,这样做的效果是,只需SELECT
从视图中执行简单操作,而无需ORDER BY
在外部查询上执行任何操作,就会按所需的顺序返回行。这从来没有得到保证,在 SQL Server 2005 中,逻辑被添加到优化器中,TOP 100 PERCENT
在这种情况下,优化器在逻辑上是冗余的。未来可能会发生同样的情况,因为OFFSET 0 ROWS
它同样是多余的。
就我个人而言,我希望任何多余的工程努力都可以用于改进优化,因此这种黑客攻击并不是首先必要的!
归档时间: |
|
查看次数: |
2110 次 |
最近记录: |