CTE Recursion Performance
CTE全名是Common Table Expression,语法基础请参考MSDN文档:https://msdn.microsoft.com/zh-cn/library/ms175972.aspx。
CTE Recursion诞生之时,着实让人惊艳了一把。被很多吃瓜群众以讹传讹之后,“慢”似乎成了CTE Recursion最大的原罪。
很多时候,用到CTE Recursion的场景,无非是千八百条的数据量,最大也不过万八千条,所以“慢”算不上个问题。直到前几天,一个群友问:500W的数据做CTE递归时,怎么做性能优化……
结论:
- 合理的索引会极大的提升CTE Recursion的性能;
- 根据实验结果猜测: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的更多相关文章
- TSql CTE 递归原理探究
CTE是如何进行递归的?产生递归的条件有三个,分别是 初始值 自身调用自身 结束递归的条件 1,示例代码 ;with cte as ( as jd union all as jd from cte ) ...
- SQL笔记 - CTE递归实例:显示部门全称
昨天在整理JS的Function时,示例是一个递归函数.说起递归,想起前段时间在搞CTE,那个纠结呀,看似容易,可我总抓不住门道,什么递归条件,什么结束条件,一头雾水...今天一大早就爬起来,果然不负 ...
- Chapter 6 — Improving ASP.NET Performance
https://msdn.microsoft.com/en-us/library/ff647787.aspx Retired Content This content is outdated and ...
- SQL Server CTE 递归查询全解
在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...
- SQL Server CTE 递归查询全解 -- 转 学习
在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...
- SQL Server CTE 递归查询全解(转载)
在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...
- CTE 递归查询全解
TSQL脚本能实现递归查询,用户使用共用表表达式 CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询.本文详细介绍CTE递归调用的特性和使用示例,递归查询 ...
- 利用临时表实现CTE递归查询
一.CTE递归查询简介 --CTE递归查询终止条件在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递 ...
- Performance Monitor4:监控SQL Server的IO性能
SQL Server的IO性能受到物理Disk的IO延迟和SQL Server内部执行的IO操作的影响.在监控Disk性能时,最主要的度量值(metric)是IO延迟,IO延迟是指从Applicati ...
随机推荐
- POS tagging的解釋
轉錄文章~~ 什么是词性标注(POS tagging) Tue, 04/13/2010 - 10:36 — Fuller 词性标注也叫词类标注,POS tagging是part-of-speech t ...
- jquery选择器取值和url正则匹配
用到的简单jquery知识,简单总结一下,一是能加深自己的记忆,二是方便自己以后查看.常言道"好记性不如烂笔头",要养成常总结.常记录的好习惯.慢慢的发现jquery很有意思,很强 ...
- C#Socket编程socket.Connect权限出错问题及解决
最近使用Vs2010编写Socket程序,客户端在调用socket.Connect()时,总是出现: 请求“System.Net.SocketPermission, System, Version=4 ...
- jQuery AJAX实现调用页面后台方法
1.新建demo.aspx页面.2.首先在该页面的后台文件demos.aspx.cs中添加引用. using System.Web.Services; 3.无参数的方法调用. 大家注意了,这个版本不能 ...
- sqlserver触发器如何将一个库中的数据插入到另外一个库中
需求:实现的功能就是,查询当前表的所有信息,插入到另外一个库中(同一台机器,同一个SqlServer) 解决:insert into dB2.dbo.TB2 select * from db1.dbo ...
- Win10获取管理员/administrator权限的方法
与Win7不同,Win10右键文件夹菜单,是没有“获取管理员权限”这个功能的,但是有时候我们偏偏需要用到这个功能,怎么办呢,可以按照这个办法实现:把下面的这一段代码复制下来放在文本文档中,然后另存为. ...
- iOS GCD多线程介绍
GCD:是纯C语言写的,是苹果公司为多核的并行运算提出的解决方案. GCD的两个核心概念: - 任务 - 队列 将任务添加到队列中 GCD会自动将队列中的任务取出,放到对应的线程中执行 任务的取出遵循 ...
- Why Doesn’t Drag-and-Drop work when my Application is Running Elevated? – A: Mandatory Integrity Control and UIPI(转载)
f you run notepad elevated (Right click | Run as Administrator), and you try and drag-and-drop a fil ...
- .NET Framework(一)
.NET Framework:即Microsoft .NET Framework,它是用于Windows的新托管代码编程模型.它强大功能与新技术结合起来,用于构建具有视觉上引人注目的用户体验的应用程序 ...
- dedecms修改templets为别的名字
修改templets模板文件夹的方法: 首先找到系统配置文件common.inc.php,此文件存放在Include目录下,打开common.inc.php来修改默认模板目录templets, 查找: ...