SQL点滴10—使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比

简介: 今天偶尔看到sql中也有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表中选择各个年份共有共有多少客户订购了商品

  •  第一种写法,我们可以写成这样
     
       
    1 select YEAR (o.orderdate) orderyear, COUNT ( distinct (custid)) numCusts
    2 from Sales.Orders o
    3 group by YEAR (o.orderdate)
    4 go
    要注意的是如果把group by YEAR(o.orderdata)换成group by orderyear就会出错,这里涉及到sql语句的执行顺序问题,有时间再了解一下          
  • 第二种写法,
     
       
    1 select orderyear, COUNT ( distinct (custid))numCusts
    2 from ( select YEAR (orderdate) as orderyear,custid from sales.orders) as D
    3 group by orderyear
    4 go
    在from语句中先得到orderyear,然后再select语句中就不会出现没有这个字段的错误了
  • 第三种写法,
     
       
    1 select orderyear, COUNT ( distinct (custid)) numCusts
    2 from ( select YEAR (orderdate),custid from sales.orders) as D(orderyear,custid)
    3 group by orderyear
    4 go
    在as D后面加上选择出的字段,是不是更加的清楚明了呢!
  • 第四种写法,with出场了
     
       
    1 with c as (
    2 select YEAR (orderdate) orderyear, custid from sales.orders)
    3 select orderyear, COUNT ( distinct (custid)) numCusts from c group by orderyear
    4 go
    with可以使语句更加的经凑,下面是权威解释。  
        
    指定临时命名的结果集,这些结果集称为公用表表达式 (CTE)。该表达式源自简单查询,并且在单条 SELECT、INSERT、UPDATE、MERGE 或 DELETE 语句的执行范围内定义。该子句也可用在 CREATE VIEW 语句中,作为该语句的 SELECT 定义语句的一部分。公用表表达式可以包括对自身的引用。这种表达式称为递归公用表达式。               

                                                ----MSDN

  • 第五种写法,也可以借鉴第三种写法,这样使语句更加清楚明了,便于维护
     
       
    1 with c(orderyear,custid) as (
    2   select YEAR (orderdate),custid from sales.orders)
    3   select orderyear, COUNT ( distinct (custid)) numCusts from c group by c.orderyear
    4   go
    上面5中写法都得到相同的结果,如下图1:img_a6a307475d1295893e75437cd1a61029.png图1

添加计算

  • 现在要求要求计算出订单表中每年比上一年增加的客户数目,这个稍微复杂
     
       
    1 with yearcount as (
    2   select YEAR (orderdate) orderyear, COUNT ( distinct (custid)) numCusts from sales.orders group by YEAR (orderdate))
    3   select cur.orderyear curyear,cur.numCusts curNumCusts,prv.orderyear prvyear,prv.numCusts prvNumCusts,cur.numCusts - prv.numCusts growth
    4   from yearcount cur left join yearcount prv on cur.orderyear = prv.orderyear + 1
    5 go
    这里两次使用到with结果集。查询得到的结果如下图2
    img_c35950dbbc3c1dc9bdced3ddfa2d4d94.png
    图2

复杂的计算

  • 查找客户id,这些客户和所有来自美国的雇员至少有一笔交易记录,查询语句如下
     
       
    1 with TheseEmployees as (
    2 select empid from hr.employees where country = ' USA ' ),
    3 CharacteristicFunctions as (
    4 select custid,
    5 case when custid in ( select custid from sales.orders as o where o.empid = e.empid) then 1 else 0 end as charfun
    6 from sales.customers as c cross join TheseEmployees as e)
    7 select custid, min (charfun) from CharacteristicFunctions group by custid having min (charfun) = 1
    8 go
    这里嵌套with语句,第with语句查找美国雇员的id,第二个语句使用这个结果和拥有客户的客户id和拥有关系标识做笛卡尔积运算。最后从这个笛卡尔积中通过标识找到最终的custid。
    结果如下图3
    img_ad130d0f4d1d4b866b3437cd2474ffed.png
    图3

这里只有简单地介绍,没有深入,高手们不要见笑啊。



---------------------------------------------------------分界线----------------------------------------------------------

with语句和子查询的性能比较

在博友SingleCat的提醒下,对with语句做一些性能测试,这里使用的测试工具是SQL Server Profile。我选择了最后一个语句,因为这个语句比较复杂一点。开始的时候单独执行一次发现他们的差别不大,就差几个毫秒,后来想让他们多执行几次,连续执行10

次看看执行的结果。下面贴出测试用的语句。

 
 
1 /* with查询 */
2 declare @withquery varchar ( 5000 )
3 declare @execcount int = 0
4 set @withquery = ' with TheseEmployees as(
5 select empid from hr.employees where country=N '' USA '' ),
6 CharacteristicFunctions as(
7 select custid,
8 case when custid in (select custid from sales.orders as o where o.empid=e.empid) then 1 else 0 end as charfun
9 from sales.customers as c cross join TheseEmployees as e)
10 select custid from CharacteristicFunctions group by custid having min(charfun)=1 order by custid
11 '
12 while @execcount < 10
13 begin
14 exec ( @withquery );
15 set @execcount = @execcount + 1
16 end
17
18 /* 子查询 */
19 declare @subquery varchar ( 5000 )
20 declare @execcount int = 0
21 set @subquery = ' select custid from Sales.Orders where empid in
22 (select empid from HR.Employees where country = N '' USA '' ) group by custid
23 having count(distinct empid)=(select count(*) from HR.Employees where country = N '' USA '' );
24 '
25 while @execcount < 10
26 begin
27 exec ( @subquery );
28 set @execcount = @execcount + 1
29 end

SQL Server Profile中截图如下

img_eec02b8ab3bc50c54a6926c0cf088806.png

从图中可以看到子查询语句的执行时间要少于with语句,我觉得主要是with查询中有一个cross join做了笛卡尔积的关系,于是又实验了上面的那个简单一点的,下面是测试语句。

 
 
1 /* with语句 */
2 declare @withquery varchar ( 5000 )
3 declare @execcount int = 0
4 set @withquery = ' with c(orderyear,custid) as(
5 select YEAR(orderdate),custid from sales.orders)
6 select orderyear,COUNT(distinct(custid)) numCusts from c group by c.orderyear '
7 while @execcount < 100
8 begin
9 exec ( @withquery );
10 set @execcount = @execcount + 1
11 end
12
13 /* 子查询 */
14 declare @subquery varchar ( 5000 )
15 declare @execcount int = 0
16 set @subquery = ' select orderyear,COUNT(distinct(custid)) numCusts
17 from (select YEAR(orderdate),custid from sales.orders) as D(orderyear,custid)
18 group by orderyear '
19 while @execcount < 100
20 begin
21 exec ( @subquery );
22 set @execcount = @execcount + 1
23 end

 

这次做10次查询还是没有多大的差距,with语句用10个duration,子查询用了11个,有时候还会翻过来。于是把执行次数改成100,这次还是子查询使用的时间要少,截图如下

img_6cbc76f08b80e1ab0b60f850475a1fa9.png

最终结论,子查询好比with语句效率高。

作者:Tyler Ning
出处:http://www.cnblogs.com/tylerdonet/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,如有问题,可以通过以下邮箱地址williamningdong@gmail.com  联系我,非常感谢。

目录
相关文章
|
1月前
|
SQL 存储 关系型数据库
如何巧用索引优化SQL语句性能?
本文从索引角度探讨了如何优化MySQL中的SQL语句性能。首先介绍了如何通过查看执行时间和执行计划定位慢SQL,并详细解析了EXPLAIN命令的各个字段含义。接着讲解了索引优化的关键点,包括聚簇索引、索引覆盖、联合索引及最左前缀原则等。最后,通过具体示例展示了索引如何提升查询速度,并提供了三层B+树的存储容量计算方法。通过这些技巧,可以帮助开发者有效提升数据库查询效率。
133 2
|
23天前
|
SQL 存储 缓存
如何优化SQL查询性能?
【10月更文挑战第28天】如何优化SQL查询性能?
80 10
|
24天前
|
SQL 关系型数据库 MySQL
惊呆:where 1=1 可能严重影响性能,差了10多倍,快去排查你的 sql
老架构师尼恩在读者交流群中分享了关于MySQL中“where 1=1”条件的性能影响及其解决方案。该条件在动态SQL中常用,但可能在无真实条件时导致全表扫描,严重影响性能。尼恩建议通过其他条件或SQL子句命中索引,或使用MyBatis的`&lt;where&gt;`标签来避免性能问题。他还提供了详细的执行计划分析和优化建议,帮助大家在面试中展示深厚的技术功底,赢得面试官的青睐。更多内容可参考《尼恩Java面试宝典PDF》。
|
1月前
|
SQL 监控 数据库
慢SQL对数据库写入性能的影响及优化技巧
在数据库管理系统中,慢SQL(即执行缓慢的SQL语句)不仅会影响查询性能,还可能对数据库的写入性能产生显著的不利影响
|
1月前
|
SQL 关系型数据库 PostgreSQL
遇到SQL 子查询性能很差?其实可以这样优化
遇到SQL 子查询性能很差?其实可以这样优化
98 2
|
1月前
|
SQL Oracle 关系型数据库
Oracle SQL:了解执行计划和性能调优
Oracle SQL:了解执行计划和性能调优
57 1
|
1月前
|
SQL 存储 数据库
慢SQL对数据库写入性能的影响及优化技巧
在数据库管理系统中,慢SQL(即执行缓慢的SQL语句)不仅会影响查询性能,还可能对数据库的写入性能产生显著的不利影响
|
1月前
|
SQL 数据处理 数据库
SQL语句优化与查询结果优化:提升数据库性能的实战技巧
在数据库管理和应用中,SQL语句的编写和查询结果的优化是提升数据库性能的关键环节
|
1月前
|
SQL 存储 数据库
慢SQL对数据库写入性能的影响及优化策略
在数据库管理系统中,慢SQL(即执行缓慢的SQL语句)不仅会影响查询性能,还可能对数据库的写入性能产生不利影响
|
2月前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")

热门文章

最新文章

下一篇
无影云桌面