SQL点滴10—使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比
原文:SQL点滴10—使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比
今天偶尔看到sql中也有with关键字,好歹也写了几年的sql语句,居然第一次接触,无知啊。看了一位博主的文章,自己添加了一些内容,做了简单的总结,这个语句还是第一次见到,学习了。我从简单到复杂地写,希望高手们不要见笑。下面的sql语句设计到三个表,表的内容我用txt文件复制进去,这里不妨使用上一个随笔介绍的建立端到端的package的方法将这些表导入到数据库中,具体的就不说了。
从这里下载文件employees.txt,customers.txt,orders.txt
参考文章:http://www.cnblogs.com/wwan/archive/2011/02/24/1964279.html
使用package导入数据:http://www.cnblogs.com/tylerdonet/archive/2011/04/17/2017471.html
简单的聚合
从orders表中选择各个年份共有共有多少客户订购了商品
- 第一种写法,我们可以写成这样
select YEAR(o.orderdate) orderyear,COUNT(distinct(custid)) numCusts
from Sales.Orders o
group by YEAR(o.orderdate)
go要注意的是如果把group by YEAR(o.orderdata)换成group by orderyear就会出错,这里涉及到sql语句的执行顺序问题,有时间再了解一下
- 第二种写法,
select orderyear,COUNT(distinct(custid))numCusts
from (select YEAR(orderdate) as orderyear,custid from sales.orders) as D
group by orderyear
go在from语句中先得到orderyear,然后再select语句中就不会出现没有这个字段的错误了
- 第三种写法,
select orderyear,COUNT(distinct(custid)) numCusts
from (select YEAR(orderdate),custid from sales.orders) as D(orderyear,custid)
group by orderyear
go在as D后面加上选择出的字段,是不是更加的清楚明了呢!
- 第四种写法,with出场了
with c as(
select YEAR(orderdate) orderyear, custid from sales.orders)
select orderyear,COUNT(distinct(custid)) numCusts from c group by orderyear
gowith可以使语句更加的经凑,下面是权威解释。
指定临时命名的结果集,这些结果集称为公用表表达式 (CTE)。该表达式源自简单查询,并且在单条 SELECT、INSERT、UPDATE、MERGE 或 DELETE 语句的执行范围内定义。该子句也可用在 CREATE VIEW 语句中,作为该语句的 SELECT 定义语句的一部分。公用表表达式可以包括对自身的引用。这种表达式称为递归公用表达式。
----MSDN
- 第五种写法,也可以借鉴第三种写法,这样使语句更加清楚明了,便于维护
with c(orderyear,custid) as(
select YEAR(orderdate),custid from sales.orders)
select orderyear,COUNT(distinct(custid)) numCusts from c group by c.orderyear
go上面5中写法都得到相同的结果,如下图1:
图1
添加计算
- 现在要求要求计算出订单表中每年比上一年增加的客户数目,这个稍微复杂
with yearcount as(
select YEAR(orderdate) orderyear,COUNT(distinct(custid)) numCusts from sales.orders group by YEAR(orderdate))
select cur.orderyear curyear,cur.numCusts curNumCusts,prv.orderyear prvyear,prv.numCusts prvNumCusts,cur.numCusts-prv.numCusts growth
from yearcount cur left join yearcount prv on cur.orderyear=prv.orderyear+1
go这里两次使用到with结果集。查询得到的结果如下图2
图2
复杂的计算
- 查找客户id,这些客户和所有来自美国的雇员至少有一笔交易记录,查询语句如下
with TheseEmployees as(
select empid from hr.employees where country='USA'),
CharacteristicFunctions as(
select custid,
case when custid in (select custid from sales.orders as o where o.empid=e.empid) then 1 else 0 end as charfun
from sales.customers as c cross join TheseEmployees as e)
select custid,min(charfun) from CharacteristicFunctions group by custid having min(charfun)=1
go这里嵌套with语句,第with语句查找美国雇员的id,第二个语句使用这个结果和拥有客户的客户id和拥有关系标识做笛卡尔积运算。最后从这个笛卡尔积中通过标识找到最终的custid。
结果如下图3
图3
这里只有简单地介绍,没有深入,高手们不要见笑啊。
---------------------------------------------------------分界线----------------------------------------------------------
with语句和子查询的性能比较
在博友SingleCat的提醒下,对with语句做一些性能测试,这里使用的测试工具是SQL Server Profile。我选择了最后一个语句,因为这个语句比较复杂一点。开始的时候单独执行一次发现他们的差别不大,就差几个毫秒,后来想让他们多执行几次,连续执行10
次看看执行的结果。下面贴出测试用的语句。
/*with查询*/
declare @withquery varchar(5000)
declare @execcount int=0
set @withquery='with TheseEmployees as(
select empid from hr.employees where country=N''USA''),
CharacteristicFunctions as(
select custid,
case when custid in (select custid from sales.orders as o where o.empid=e.empid) then 1 else 0 end as charfun
from sales.customers as c cross join TheseEmployees as e)
select custid from CharacteristicFunctions group by custid having min(charfun)=1 order by custid
'
while @execcount<10
begin
exec (@withquery);
set @execcount=@execcount+1
end
/*子查询*/
declare @subquery varchar(5000)
declare @execcount int=0
set @subquery='select custid from Sales.Orders where empid in
(select empid from HR.Employees where country = N''USA'') group by custid
having count(distinct empid)=(select count(*) from HR.Employees where country = N''USA'');
'
while @execcount<10
begin
exec (@subquery);
set @execcount=@execcount+1
end
从SQL Server Profile中截图如下
从图中可以看到子查询语句的执行时间要少于with语句,我觉得主要是with查询中有一个cross join做了笛卡尔积的关系,于是又实验了上面的那个简单一点的,下面是测试语句。
/*with语句*/
declare @withquery varchar(5000)
declare @execcount int=0
set @withquery='with c(orderyear,custid) as(
select YEAR(orderdate),custid from sales.orders)
select orderyear,COUNT(distinct(custid)) numCusts from c group by c.orderyear'
while @execcount<100
begin
exec (@withquery);
set @execcount=@execcount+1
end
/*子查询*/
declare @subquery varchar(5000)
declare @execcount int=0
set @subquery='select orderyear,COUNT(distinct(custid)) numCusts
from (select YEAR(orderdate),custid from sales.orders) as D(orderyear,custid)
group by orderyear'
while @execcount<100
begin
exec (@subquery);
set @execcount=@execcount+1
end
这次做10次查询还是没有多大的差距,with语句用10个duration,子查询用了11个,有时候还会翻过来。于是把执行次数改成100,这次还是子查询使用的时间要少,截图如下
最终结论,子查询好比with语句效率高。
SQL点滴10—使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比的更多相关文章
- 使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比
今天偶尔看到sql中也有with关键字,好歹也写了几年的sql语句,居然第一次接触,无知啊.看了一位博主的文章,自己添加了一些内容,做了简单的总结,这个语句还是第一次见到,学习了.我从简单到复杂地写, ...
- SQL语句汇总(三)——聚合函数、分组、子查询及组合查询
拖了一个星期,终于开始写第三篇了.走起! 聚合函数: SQL中提供的聚合函数可以用来统计.求和.求最值等等. 分类: –COUNT:统计行数量 –SUM:获取单个列的合计值 –AVG:计算某个列的平均 ...
- 牛逼哄哄的PageHelper分页插件到底是怎么实现的?网友:给我10分钟,给你写一个~
Hi,各位读者们 PageHelper是一款好用的开源免费的Mybatis第三方物理分页插件,其实我并不想加上好用两个字,但是为了表扬插件作者开源免费的崇高精神,我毫不犹豫的加上了好用一词作为赞美. ...
- python学习(10)字典学习,写一个三级菜单程序
学习了字典的应用.按老师的要求写一个三级菜单程序. 三级菜单程序需求如下: 1.深圳市的区--街道--社区---小区4级 2.建立一个字典,把各级区域都装进字典里 3.用户可以从1级进入2级再进入3级 ...
- 表查询语句及使用-连表(inner join-left join)-子查询
一.表的基本查询语句及方法 from. where. group by(分组).having(分组后的筛选).distinct(去重).order by(排序). limit(限制) 1.单表查询: ...
- 如何写一个像btgoogle一样的12306泄露数据查询
demo地址:http://www.btgoogle.com/12306/ 圣诞节,12306送给了我们一个大礼物.大约 14w的数据泄露, 看网上都沸沸扬扬的.开始也准备找一个数据库来看看,随后,我 ...
- DAY5 php + mysql 写一个简单的sql注入平台
php mysql 在浏览器输入用户名,去数据库查询.查到则显示在浏览器,查不到则显示空. sql 里面三个字段 id username password create table t1 (id in ...
- 微信小程序开发入门:10分钟从0开始写一个hello-world
小程序开发需要三个描述整体程序的app文件 和 一个描述多个页面的 pages文件夹. (1)三个app文件分别是app.js,app.json,app.wxss. app.js文件是脚本文件处理一些 ...
- js if语句只写一个参数是什么意思?
如 var a=0:if(!a){...}; avascript中以下值会被转换为false false undefined null 0 -0 NaN ""
随机推荐
- HDU 3103 Shoring Up the Levees(计算几何 搜寻区域)
主题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3103 Problem Description The tiny country of Waterlog ...
- EntityFramework6 用 PostgreSQL
开篇 1.这是自己第一篇博客,希望能够坚持下去.. 2.可能技术比较初级,大神看不下的话,多鼓励.. 3.开发环境为 vs2013,.net framework 4.5; 开始 1.安装entityf ...
- [SignalR]Groups操作——后续
原文:[SignalR]Groups操作——后续 继续http://www.cnblogs.com/YanZhiwei/p/3359175.html之前,那怎么实现发送的消息推送到隶属于这个组的用户呢 ...
- extjs_09_定义自己的页面组件
1.项目截图 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWRhbV93enM=/font/5a6L5L2T/fontsize/400/fill/I0J ...
- 采用Flume实时采集和处理数据
它已成功安装Flume在...的基础上.本文将总结使用Flume实时采集和处理数据,详细过程,如下面: 第一步,在$FLUME_HOME/conf文件夹下,编写Flume的配置文件,命名为flume_ ...
- Android用户界面设计:框架布局(转)
摘要:框架布局是Android开发者组织视图控件最简单和最有效的布局之一.通过本文,你将学到所有关于框架布局的知识,它们主要用来在屏幕上组织特别的或重叠的视图控件.使用得当的话,很多有趣的Androi ...
- j2se--Socket沟通
第一次接触Socket课程设计大二,我在做一个图书馆管理系统.源代码是从互联网上下载,代码天天磨,隐约中记得有Socket这么一个单词. 第二次是去年代表学校參加"河北省电子信息职业技能大赛 ...
- (大数据工程师学习路径)第三步 Git Community Book----Git基本用法(上)
一.git的初始化 1.Git 配置 使用Git的第一件事就是设置你的名字和email,这些就是你在提交commit时的签名. $ git config --global user.name &quo ...
- POJ 2762 Going from u to v or from v to u?(强连通分量+拓扑排序)
职务地址:id=2762">POJ 2762 先缩小点.进而推断网络拓扑结构是否每个号码1(排序我是想不出来这点的. .. ).由于假如有一层为2的话,那么从此之后这两个岔路的点就不可 ...
- acdream 1431 Sum vs Product
Sum vs Product Time Limit: 4000/2000MS (Java/Others)Memory Limit: 128000/64000KB (Java/Others) Submi ...