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. Shell - 文件运算符

    文件运算符  文件运算符  描述 -b file  检测 file 是否为块设备文件 -c file  检测 file 是否为字符设备文件  -d file  检测 file 是否为目录 -e fil ...

  2. linux的grep命令

    参考文档如下: linux grep命令 grep abb15455baeb4b23ab47540272ec47eb epps-sas.log | grep operateSettleBill exp ...

  3. Two ways to create file using 'doc'.

    Here are two ways to create file using 'doc' command: Method i: copy con [file name][enter key] [con ...

  4. Premature optimization is the root of all evil.

    For all of we programmers,we should always remember that "Premature optimization is the root of ...

  5. 怎么捕获和记录SQL Server中发生的死锁

    我们知道,可以使用SQL Server自带的Profiler工具来跟踪死锁信息.但这种方式有一个很大的敝端,就是消耗很大.据国外某大神测试,profiler甚至可以占到服 务器总带宽的35%,所以,在 ...

  6. 表单提交对chrome记住密码的影响

    在处理注册.登录等含有用户名,密码的元素的表单时,chrome会主动的提示记住密码,然而这个功能在用户名的选择上真是耐人寻味,它总是寻找离password input控件最近的那一个文本框的内容,作为 ...

  7. oracle解析xml(增加对9i版本的支持)

    --方法1  SELECT * FROM  XMLTABLE('$B/DEAL_BASIC/USER_DEAL_INFO' PASSING     XMLTYPE('<?xml version= ...

  8. SpringMVC4+thymeleaf3的一个简单实例(篇五:页面和MySql的数据交互-展示以及存储)

    这一篇将介绍怎样把页面数据保存的MySQL数据库,并将数据库内容展示到页面上.首先做一个基础工作,添加以下jar到lib:1: mysql-connector-Java-5.1.40-bin.jar ...

  9. J2se中的声音---AudioPlayer

    1 package cn.gp.tools; import java.io.FileInputStream; import java.io.FileNotFoundException; import ...

  10. PHP 用户注册

    注册页面 reg.html 负责收集用户填写的注册信息.教程里只列出关键的代码片段,完整的代码附在本节最后. 注册表单 <fieldset> <legend>用户注册</ ...