惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
爱范儿
爱范儿
H
Help Net Security
V
Visual Studio Blog
J
Java Code Geeks
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
MyScale Blog
MyScale Blog
The Cloudflare Blog
Martin Fowler
Martin Fowler
D
Docker
腾讯CDC
F
Fortinet All Blogs
雷峰网
雷峰网
GbyAI
GbyAI
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
博客园 - 聂微东
博客园 - 叶小钗

博客园 - 谢堂文(Darren Xie)

Camstar MES 5.8 發現Ajax事件失效 验证(C#和正则表达式) 新MES已上線 Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine Microsoft SQL Server Reporting Services (SSRS)报表技巧之在图表中增加参考线 MS SQL,数据库增长时众多表中谁是你关注的目标 想个法子找出性能差的SQL T-SQL 日期处理总结 从MS SQL删除大数据说开去 一步一步用C#写一个检查SQL Server假死警报服务 MM的Windows 7 登录密码忘记之后 基于工作实际需求的Ext.Net和C#搭配应用之一 取出网域(AD)中所有计算机名及位置描述等信息 MS SQL自定义字符串拆分函数的惨痛经历 2012,我的C#全能Excel操作(无需Office,不使用XML) 代码注释规范 2012年开发者该做的11件事 取出AD中一個組的所有成員信息(C#實現功能配合EXT做的界面) 一個文件文件和路徑的類 C#路径/文件/目录/I/O常见操作汇总
SQL调优日记之发挥SQL性能与你的写法有关--对比三种方式实...
谢堂文(Darren Xie) · 2012-05-15 · via 博客园 - 谢堂文(Darren Xie)

今天再次改老系统,看着前边的师兄留下的SQL,就想起了MS SQL 7.5和SQL2000。可能很多人都还没有习惯新版本(05版之后)的SQL语法,还是用以前开发MS SQL2000的方式实现功能,但是多少人会明白,换一种写法后,性能却相差十倍百倍呢!

我用来做例子的是我们MES系统用到的一段简单功能T-SQL,都是使用同一个库、相同的表、相同的逻辑:

开始前先记录时间,计算完成后看用了多少时间。

我先用推荐的语法来写的方式,代码1是好的写法,由于是在我们系统的情景下描述的,看管不可照抄,只说明性能的差别。

代码1:

用WITH,把各个逻辑分开处理,再终合出最后结果,推荐!

   1:  declare @P INT,@T DATETIME;
   2:  SELECT @P=1,@T=GETDATE();
   3:  ;WITH R0 --
   4:      AS (
   5:          SELECT TOP 1 M.WPCODE,t.RID,MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO FROM MES_WFCIO M,MES_WFCIODTL t  
   6:              WHERE M.RID=t.RID AND WFCNO='JSAC00334D-033-001'
   7:              ORDER BY t.RID DESC
   8:      )                
   9:      ,R1 
  10:      AS (
  11:          SELECT TOP 1 M.WPCODE,t.RID,M.MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO FROM MES_WFCIO M,MES_WFCIODTL t,R0
  12:              WHERE M.RID=t.RID 
  13:              AND M.MACNO=R0.MACNO
  14:              AND M.RID<>R0.RID
  15:              AND M.WPCODE=R0.WPCODE
  16:              ORDER BY t.RID DESC
  17:      )
  18:      ,R2 
  19:      AS (
  20:          SELECT WO FROM R0
  21:          UNION
  22:          SELECT WO FROM R1
  23:      )
  24:      ,R3 
  25:      AS (
  26:          SELECT DISTINCT MASTERNUM FROM R2,WO WHERE R2.WO=WO.WONUM
  27:      )
  28:      SELECT @P=COUNT(*) FROM R3;
  29:      select @P AS [計算結果1];
  30:  SELECT DATEDIFF(ms,@T,getdate()) as [方法1用時];

代码2:

这是2000的时候多数人用的方式,计算过程多用临时表,不推荐!

   1:  declare @P INT,@T DATETIME;
   2:  SELECT @P=1,@T=GETDATE();
   3:  SELECT TOP 1 M.WPCODE,t.RID,MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO 
   4:      INTO #R0
   5:      FROM MES_WFCIO M,MES_WFCIODTL t  
   6:      WHERE M.RID=t.RID AND WFCNO='JSAC00334D-033-001'
   7:      ORDER BY t.RID DESC;
   8:   
   9:  SELECT TOP 1 M.WPCODE,t.RID,M.MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO 
  10:      INTO #R1
  11:      FROM MES_WFCIO M,MES_WFCIODTL t,#R0 R0
  12:      WHERE M.RID=t.RID 
  13:      AND M.MACNO=R0.MACNO
  14:      AND M.RID<>R0.RID
  15:      AND M.WPCODE=R0.WPCODE
  16:      ORDER BY t.RID DESC;
  17:   
  18:  SELECT WO INTO #R2 FROM #R0
  19:  UNION
  20:  SELECT WO FROM #R1;
  21:   
  22:  SELECT DISTINCT MASTERNUM 
  23:      INTO #R3
  24:       FROM #R2 R2,WO 
  25:      WHERE R2.WO=WO.WONUM;
  26:   
  27:  SELECT @P=COUNT(*) FROM #R3;
  28:  select @P AS [計算結果2];
  29:  SELECT DATEDIFF(ms,@T,getdate()) as [方法2用時];
  30:   
  31:  drop table #R0,#R1,#R2,#R3;

代码3:

强逻辑人员的写法,子查询方式,不推荐!

   1:  declare @P INT,@T DATETIME;
   2:  SELECT @P=1,@T=GETDATE();
   3:  SELECT @P=COUNT(*) 
   4:      FROM (SELECT DISTINCT MASTERNUM 
   5:          FROM (SELECT WO 
   6:                  FROM (SELECT TOP 1 M.WPCODE,t.RID,MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO 
   7:                          FROM MES_WFCIO M,MES_WFCIODTL t  
   8:                          WHERE M.RID=t.RID AND WFCNO='JSAC00334D-033-001'
   9:                          ORDER BY t.RID DESC) x
  10:                      UNION
  11:                      SELECT WO FROM (SELECT TOP 1 M.WPCODE,t.RID,M.MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO 
  12:              FROM MES_WFCIO M,MES_WFCIODTL t,(SELECT TOP 1 M.WPCODE,t.RID,MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO 
  13:                  FROM MES_WFCIO M,MES_WFCIODTL t  
  14:                  WHERE M.RID=t.RID AND WFCNO='JSAC00334D-033-001'
  15:                  ORDER BY t.RID DESC) R0
  16:              WHERE M.RID=t.RID
  17:              AND M.MACNO=R0.MACNO
  18:              AND M.RID<>R0.RID
  19:              AND M.WPCODE=R0.WPCODE
  20:              ORDER BY t.RID DESC)R1) R2,WO 
  21:          WHERE R2.WO=WO.WONUM)R3;
  22:  select @P AS [計算結果3];
  23:  SELECT DATEDIFF(ms,@T,getdate())  as [方法3用時];

看看执行的结果对比:

第一种写法用时不到1毫秒;

第二种写法用时56毫秒;

第三种写法用时不到1毫秒;

image

再单独执行,代码1用了3毫秒,从Messages中看到只有两条信息,也就是只操作了两个结果表对象;

image

image

代码2用了63毫秒,从Messages中看到只有两条信息,也就是只操作了六个结果表对象;

image

image

代码3用了3毫秒,从Messages中看到只有两条信息,也就是只操作了两个结果表对象;

image

image

从以上的对比结果来看,用with和用子查询的方式性能差不多,但是子查询的写法代码很难维护,用WITH的方式逻辑明确,代码重用高,易维护,性能优越;用临时表的方式逻辑也明确,但是性能差。用WITH和用子查询的方式都可以用到SQL的同时执行,用临时表就只能是按顺序执行了。

当你要对SQL进行性能调优时,除了考虑索引、统计信息、分区表、硬件升级和归档数据外,也建议考虑评估SQL的写法。

原创,转载请注明出处:http://www.cnblogs.com/YIYUMENG