Beg*_*ner 10 sql t-sql sql-server performance
使用递归CTE的超快速DISTINCT:
USE tempdb;
GO
DROP TABLE dbo.Test;
GO
CREATE TABLE
dbo.Test
(
data INTEGER NOT NULL,
);
GO
CREATE CLUSTERED INDEX c ON dbo.Test (data);
GO
-- Lots of duplicated values
INSERT dbo.Test WITH (TABLOCK)
(data)
SELECT TOP (5000000)
ROW_NUMBER() OVER (ORDER BY (SELECT 0)) / 117329
FROM master.sys.columns C1,
master.sys.columns C2,
master.sys.columns C3;
GO
SET STATISTICS TIME ON;
-- 1591ms CPU
SELECT DISTINCT
data
FROM dbo.Test;
Run Code Online (Sandbox Code Playgroud)
- 15ms CPU
WITH RecursiveCTE
AS (
SELECT data = MIN(T.data)
FROM dbo.Test T
UNION ALL
SELECT R.data
FROM (
-- A cunning way to use TOP in the recursive part of a CTE Smile
SELECT T.data,
rn = ROW_NUMBER() OVER (ORDER BY T.data)
FROM dbo.Test T
JOIN RecursiveCTE R
ON R.data < T.data
) R
WHERE R.rn = 1
)
SELECT *
FROM RecursiveCTE
OPTION (MAXRECURSION 0);
SET STATISTICS TIME OFF;
GO
DROP TABLE dbo.Test;
Run Code Online (Sandbox Code Playgroud)
递归CTE效率提高了100倍:-)这种加速对我目前的项目非常有价值,但我不确定这种方法在哪种情况下是有益的.
说实话:我不明白为什么这会加快查询速度以及为什么数据库本身无法进行此优化.你能解释一下这是如何工作的以及它为何如此有效吗?
编辑:我在sybase上看到了类似的效果,因此这种方法似乎对sql-server无效.
子问题:递归CTE对其他数据库系统也有用吗?
保罗怀特在他的帖子" 性能调整整个查询计划 "中找到了不同的价值观部分,详细解释了这个"技巧" .
为什么数据库本身无法进行优化?
递归CTE对其他数据库系统也有用吗?
优化器并不完美,它没有实现所有可能的技术.人们要求微软实施它.请参阅此连接项目实施索引跳过扫描.它被关闭为Will Not Fix,但这并不意味着它将来不会被解决.其他DBMS可能已经实现了它(Connect item表示Oracle实现了这种优化).如果在DBMS引擎中实现这种优化,则不需要此"技巧",优化器将根据可用统计信息选择计算结果的最佳方法.
我不明白为什么这会加快查询速度.
我不确定这种方法在哪种情况下是有益的
简单DISTINCT查询扫描整个索引."扫描"意味着它从磁盘读取索引的每个页面并聚合内存(或tempdb)中的值以获取不同值的列表.
如果您知道该表有很多行,但只有很少的不同值,那么读取所有这些重复值是浪费时间.递归CTE强制服务器为第一个不同的值寻找索引,然后为第二个值寻找索引,依此类推."Seek"表示服务器在索引中使用二进制搜索来查找值.通常一次搜索只需要从磁盘读取几页."索引"是一棵平衡的树.
如果表只有很少的不同值,那么寻找几次比读取索引的所有页面要快.另一方面,如果存在许多不同的值,那么顺序读取所有页面比寻找每个连续值更快.这应该可以让您了解这种方法在哪些情况下是有益的.
显然,如果表很小,扫描它会更快.只有当表变得"足够大"时,才会开始看到性能上的差异.
关于dba.se有一个相关的问题:是否有可能获得针对distinct/group by的基于搜索的并行计划?