CTE全名是Common Table Expression,语法基础请参考MSDN文档:https://msdn.microsoft.com/zh-cn/library/ms175972.aspx

CTE Recursion诞生之时,着实让人惊艳了一把。被很多吃瓜群众以讹传讹之后,“慢”似乎成了CTE Recursion最大的原罪。

很多时候,用到CTE Recursion的场景,无非是千八百条的数据量,最大也不过万八千条,所以“慢”算不上个问题。直到前几天,一个群友问:500W的数据做CTE递归时,怎么做性能优化……

结论:

  1. 合理的索引会极大的提升CTE Recursion的性能;
  2. 根据实验结果猜测:Sql Server2016对CTE Recursion做了优化,缺失合理索引的前提下,性能有极大的提升(受测试样本影响,结果可能不准确。无论如何,索引可以帮到你)。

Talk is cheap,Show me the code!所以,原因如下图(样本数据:1W零1条^^):

拒绝耍流氓,测试代码如下:

 IF OBJECT_ID('dbo.TestCte', 'U') IS NOT NULL
DROP TABLE dbo.TestCte;
GO
CREATE TABLE dbo.TestCte
(
Id VARCHAR(10) NOT NULL ,
ParentId VARCHAR(10) NULL
);
WITH cte_001
AS ( SELECT 1 AS a UNION ALL
SELECT 2 AS a UNION ALL
SELECT 3 AS a UNION ALL
SELECT 4 AS a UNION ALL
SELECT 5 AS a UNION ALL
SELECT 6 AS a UNION ALL
SELECT 7 AS a UNION ALL
SELECT 8 AS a UNION ALL
SELECT 9 AS a UNION ALL
SELECT 10 AS a )
INSERT dbo.TestCte
( Id, ParentId )
SELECT RIGHT( '' + CAST ( T01.Id AS VARCHAR(10) ), 10 ) AS Id ,
RIGHT( '' + CAST ( CEILING( T01.Id / 10 ) AS VARCHAR(10) ), 10 ) AS ParentId
FROM (
SELECT ROW_NUMBER() OVER ( ORDER BY cte_001.a ) AS Id
FROM cte_001
CROSS JOIN cte_001 AS A
CROSS JOIN cte_001 AS B
CROSS JOIN cte_001 AS C
CROSS JOIN cte_001 AS D
CROSS JOIN cte_001 AS E
CROSS JOIN (SELECT TOP 5 * FROM cte_001) AS F ) AS T01;
GO INSERT DBO.TestCte ( Id, ParentId )
VALUES ( '', NULL );
GO
 --无索引版本
SET STATISTICS TIME ON;
SET STATISTICS IO ON; IF OBJECT_ID('dbo.T', 'U') IS NOT NULL
DROP TABLE dbo.T;
GO
CREATE TABLE dbo.T
(
RN UNIQUEIDENTIFIER PRIMARY KEY,
Id VARCHAR(10) ,
ParentId VARCHAR(10) ,
Memo1 NVARCHAR(128) DEFAULT ( N'我是占位置的!我是占位置的!我是占位置的!我是占位置的!我是占位置的!' ) ,
Memo2 NVARCHAR(128) DEFAULT ( N'我是很骄傲的!我是很骄傲的!我是很骄傲的!我是很骄傲的!我是很骄傲的!' )
);
INSERT dbo.T
( RN ,
Id ,
ParentId
)
SELECT N.RN ,
N.Id ,
N.ParentId
FROM ( SELECT NEWID() AS RN ,
Id ,
ParentId
FROM dbo.TestCte
WHERE Id < 10001--测试数据量,改这里
) AS N
ORDER BY RN ASC;
GO
WITH cte_001
AS ( SELECT Id ,
ParentId
FROM dbo.T
WHERE ParentId IS NULL
UNION ALL
SELECT T01.Id ,
T01.ParentId
FROM T AS T01
INNER JOIN cte_001 AS T02 ON T02.Id = T01.ParentId
)
SELECT COUNT(*)
FROM cte_001;
 --有索引版本
SET STATISTICS TIME ON;
SET STATISTICS IO ON;
IF OBJECT_ID('dbo.T', 'U') IS NOT NULL
DROP TABLE dbo.T;
GO
CREATE TABLE dbo.T
(
RN UNIQUEIDENTIFIER PRIMARY KEY,
Id VARCHAR(10) ,
ParentId VARCHAR(10) ,
Memo1 NVARCHAR(128) DEFAULT ( N'我是占位置的!我是占位置的!我是占位置的!我是占位置的!我是占位置的!' ) ,
Memo2 NVARCHAR(128) DEFAULT ( N'我是很骄傲的!我是很骄傲的!我是很骄傲的!我是很骄傲的!我是很骄傲的!' )
);
INSERT dbo.T ( RN , Id , ParentId )
SELECT N.RN , N.Id , N.ParentId
FROM ( SELECT NEWID() AS RN , Id , ParentId
FROM dbo.TestCte
WHERE Id < 10001--测试数据量,改这里
) AS N
ORDER BY RN ASC;
GO --创建索引
CREATE NONCLUSTERED INDEX IDX_DBO_T_PARENTID_ID
ON [dbo].[T] ([ParentId], Id)
GO WITH cte_001
AS ( SELECT Id , ParentId
FROM dbo.T
WHERE ParentId IS NULL
UNION ALL
SELECT T01.Id , T01.ParentId
FROM T AS T01
INNER JOIN cte_001 AS T02 ON T02.Id = T01.ParentId
)
SELECT COUNT(*)
FROM cte_001;

CTE Recursion Performance的更多相关文章

  1. TSql CTE 递归原理探究

    CTE是如何进行递归的?产生递归的条件有三个,分别是 初始值 自身调用自身 结束递归的条件 1,示例代码 ;with cte as ( as jd union all as jd from cte ) ...

  2. SQL笔记 - CTE递归实例:显示部门全称

    昨天在整理JS的Function时,示例是一个递归函数.说起递归,想起前段时间在搞CTE,那个纠结呀,看似容易,可我总抓不住门道,什么递归条件,什么结束条件,一头雾水...今天一大早就爬起来,果然不负 ...

  3. Chapter 6 — Improving ASP.NET Performance

    https://msdn.microsoft.com/en-us/library/ff647787.aspx Retired Content This content is outdated and ...

  4. SQL Server CTE 递归查询全解

    在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...

  5. SQL Server CTE 递归查询全解 -- 转 学习

    在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...

  6. SQL Server CTE 递归查询全解(转载)

    在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...

  7. CTE 递归查询全解

    TSQL脚本能实现递归查询,用户使用共用表表达式 CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询.本文详细介绍CTE递归调用的特性和使用示例,递归查询 ...

  8. 利用临时表实现CTE递归查询

    一.CTE递归查询简介 --CTE递归查询终止条件在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递 ...

  9. Performance Monitor4:监控SQL Server的IO性能

    SQL Server的IO性能受到物理Disk的IO延迟和SQL Server内部执行的IO操作的影响.在监控Disk性能时,最主要的度量值(metric)是IO延迟,IO延迟是指从Applicati ...

随机推荐

  1. 使用ListView 时,遇到了 Your content must have a ListView whose id attribute is 'android.R.id.list' 错误

    今天在开发Android小应用的时候,使用到了ListView,在使用自己创建的listview风格的时候,就出现了如标题的错误提示信息,这个就让我纳闷了,以前也不会出现这个问题啊,而且也可以运行,赶 ...

  2. mysql隐藏文件一定要删除彻底

    之前部署自己的服务器机器的时候 机器的mysql密码是不知道的.彻底删除了软件之后还是解决不了问题,而且我把MYSQL在C盘的隐藏文件也给删除了.但是还是不行 最后我偶然发现一个方法去找隐藏问题.我之 ...

  3. Css3 常见鼠标滑过效果集合

    1.演示地址: http://yaochuxia.github.io/hover/#

  4. NSDate和NSString的转换及判定是昨天,今天,明天

    用于uidate,picker.. +(NSDate*) convertDateFromString:(NSString*)uiDate{    NSDateFormatter *formatter ...

  5. OC中的SEL解析

    OC中的SEL对象即selector对象,用来保存一个方法的地址.下面通过一个Demo来解析SEL的原理.创建一个Person类,Person.h中: #import <Foundation/F ...

  6. 文字超出DIV的边框

    已经给div设置了高宽,但是文字还是会戳出div而不是换行 鼓捣了一下好像是因为这个原因 如果全是 aaaaaaaaaaaaaaaaaaaaa 这样的纯英文,那么测试的时候是不会换行的,因为浏览器认为 ...

  7. 怎么去掉iframe的滚动条?

    <iframe name="123" src="YNJD/ynjd.htm" frameborder="0" width=" ...

  8. python - StringIO文本缓冲

    参考:http://pymotwcn.readthedocs.org/en/latest/documents/StringIO.html 类StringIO提供了一个在内存中方便处理文本的类文件(读, ...

  9. 【技术宅3】截取文件和url扩展名的N种方法

    //截取文件扩展名的N种方法   //第1种 //strrchr() 函数查找字符在指定字符串中最后一次出现的位置,如果成功,则返回其后面的字符串 //返回带有点的扩展名 function get_e ...

  10. pkg-config相关的常用指令

    pkg-config用途: 查询系统已安装库的基础信息(元信息) 1.查看所有的pkg-config库 pkg-config --list-all --list-all  列出pkg-config路径 ...