天天看点

SQL Server 查询优化一例

前几天去客户那里做性能检查优化,发现有这样一大段SQL语句,每天会执行几千次,

--一共36条相似语句,只是每条语句中的条件 病案大类 不同
select @一般医疗服务费=sum(isnull(金额,0)) from 流水帐 WITH (NOLOCK)  
where 住院号[email protected] and 项目代码 in (select 项目代码 from 收费项目表 where 病案大类='一般医疗服务费')

select @一般治疗操作费=sum(isnull(金额,0)) from 流水帐  WITH (NOLOCK) 
where 住院号[email protected] and 项目代码 in (select 项目代码 from 收费项目表 where 病案大类='一般治疗操作费')

......
......
......

select @检查用一次性医用材料费=sum(isnull(金额,0)) from 流水帐  WITH (NOLOCK) 
where 住院号[email protected] and 项目代码 in (select 项目代码 from 收费项目表 where 病案大类='检查用一次性医用材料费')

select @治疗用一次性医用材料费=sum(isnull(金额,0)) from 流水帐  WITH (NOLOCK) 
where 住院号[email protected] and 项目代码 in (select 项目代码 from 收费项目表 where 病案大类='治疗用一次性医用材料费')
           

看到这段语句,脑海中不禁浮现出这样一个情景。过年的时候,所有的亲戚,一共36个人,聚在一起吃年夜饭。一桌子的菜都上齐了,大家围坐在一起,正准备开吃,发现桌上还没筷子。这时候你妈让你去拿筷子。你去一趟厨房,拿了一双筷子递给太爷爷;再回一趟厨房,拿一双筷子递给太奶奶;再回一趟厨房,拿一双给爷爷...等筷子都拿齐了,菜凉了,你也累瘫了,大家看着你跑来跑去,都会轻声叹气,这孩子啊。。。

这种查询写法的效率实在是不高,原因有以下几点

  • 每次都得查询所有的项目费用,有多少个项目,就要查询多少次,无论某个项目的费用是否产生
  • 表中的数据有上亿条,每多一次查询所付出的成本,不容忽视
  • 如果新增一个费用项目,或者修改已有项目名称,则需要相应的修改或增加查询语句,提高了维护的复杂性

从这个查询语句的编写逻辑大致能推测出,开发人员有面向过程的编程语言经验,喜欢逐条处理数据。但SQL是面向结果的,你不需要告诉它每一步要怎么做,只要告诉它所需要的结果就可以了,它自己会选择用高效率的方式处理数据,得到结果。

如果是面向结果的你会怎么拿筷子?不用问,去一趟厨房,数好72根筷子,一起拿过来放桌上,大家一分,立马开吃。两种处理方式的成本和效率的区别显而易见。

那该怎么优化呢,参考的语句如下。这样只要访问一次表,一锅端,就可以得到所有项目的费用,再交由应用程序处理展现吧。

SELECT  SUM(ISNULL(a.金额,0))
       ,b.病案大类
FROM    住院_病人费用流水帐 a WITH (NOLOCK)
JOIN    代码_收费项目表 b
ON      a.项目代码=b.项目代码
WHERE   a.住院号[email protected]
GROUP BY b.病案大类