递归相关表达式如何加速不同的查询?

时间:2017-03-14 09:19:03

标签: sql sql-server performance tsql

我发现this post关于加快不同的查询:

使用递归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;

- 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;

递归CTE效率提高了100倍:-)这种加速对我目前的项目非常有价值,但我不确定这种方法在哪种情况下是有益的。

说实话:我不明白为什么这会加速查询的速度以及为什么数据库本身无法进行优化。你能解释一下这是如何工作的以及它为何如此有效吗?

编辑:我看到对sybase有类似的影响,所以这种方法似乎对sql-server无效。

子问题:递归CTE对其他数据库系统也有用吗?

2 个答案:

答案 0 :(得分:6)

保罗怀特解释了这个&#34;技巧&#34;在查找不同的值部分的帖子Performance Tuning the Whole Query Plan中详细了解。

  

为什么数据库本身无法进行优化?

     

递归CTE对其他数据库系统也有用吗?

优化器并不完美,并且它没有实现所有可能的技术。人们要求微软实施它。请参阅此连接项Implement Index Skip Scan。它被关闭为Won&#tt Fix,但这并不意味着它将来不会被解决。其他DBMS可能已经实现了它(Connect item表示Oracle实现了这种优化)。如果在DBMS引擎中实现这种优化,那么这个&#34;技巧&#34;不需要,优化器会根据可用的统计数据选择最优的计算结果的方法。

  

我不明白为什么这会加速查询的速度。

     

我不确定这种方法在哪种情况下是有益的

简单DISTINCT查询扫描整个索引。 &#34;扫描&#34;表示它从磁盘读取索引的每个页面并聚合内存(或tempdb)中的值以获取不同值的列表。

如果您知道该表有很多行,但只有少数不同的不同值,那么读取所有这些重复值是浪费时间。递归CTE强制服务器为第一个不同的值寻找索引,然后为第二个值寻找索引,依此类推。 &#34;寻求&#34;表示服务器在索引中使用二进制搜索来查找值。通常一次搜索只需要从磁盘读取几页。 &#34;指数&#34;是一棵平衡的树。

如果表只有很少的不同值,那么寻找几次比读取索引的所有页面要快。另一方面,如果存在许多不同的值,那么顺序读取所有页面比寻找每个连续值更快。这应该可以让您了解这种方法在哪些情况下是有益的。

显然,如果表格很小,扫描速度会更快。只有当桌子变得足够大时才会#34;你开始看到性能上的差异了。

dba.se上有一个相关的问题:Is it possible to get seek based parallel plan for distinct/group by?

答案 1 :(得分:0)

在我的机器上运行上述脚本时的注意事项。

Disctinct query =群集扫描是94%

递归查询=聚集扫描为14%

这是主要原因

分辨率查询

CPU时间= 920 ms,经过时间= 211 ms。

递归查询

CPU时间= 0 ms,经过时间= 64 ms。

在这个例子中可能是递归选项似乎很好。

但是在现实世界中,使用递归获取分析结果可能不是一个好主意。

因此你不能说,“使用递归CTE的超快速DISTINCT: