日期:2014-05-18  浏览次数:20479 次

SQL简单select奇怪问题
A.declare @s varchar(20),@i int
  set @s='1001001'
  select @i=病人ID from 住院病人登记记录 where 住院号=@s
  select * from 住院病人费用明细记录 where 病人ID=@i
B.declare @s varchar(20)
  set @s='1001001'
  select * from 住院病人费用明细记录 where 病人ID=
  (select 病人ID from 住院病人登记记录 where 住院号=@s)

这两条语句功能完全一样,返回结果也完全一样,但执行时间相差很远
A:
表 'Pub_Departments'。扫描计数 3,逻辑读 4 次,物理读 0 次,预读 0 次。
表 'Inpt_Registers'。扫描计数 1,逻辑读 5 次,物理读 0 次,预读 0 次。
表 'Inpt_Patients'。扫描计数 1,逻辑读 2 次,物理读 0 次,预读 0 次。

SQL Server 执行时间: 
  CPU 时间 = 0 毫秒,耗费时间 = 0 毫秒。

(所影响的行数为 293 行)

表 'Pub_Tariff'。扫描计数 221,逻辑读 476 次,物理读 0 次,预读 0 次。
表 'Inpt_Wastebook'。扫描计数 2,逻辑读 4 次,物理读 0 次,预读 0 次。
表 'Pub_Medicines'。扫描计数 72,逻辑读 174 次,物理读 0 次,预读 0 次。
表 'Inpt_SpecializedTrpMaster'。扫描计数 62,逻辑读 143 次,物理读 0 次,预读 0 次。
表 'Inpt_SpecializedTrpDetail'。扫描计数 2,逻辑读 426 次,物理读 0 次,预读 0 次。
表 'Inpt_TranCtnOrderMaster'。扫描计数 2,逻辑读 892 次,物理读 0 次,预读 0 次。
表 'Inpt_CtnOrderMaster'。扫描计数 273,逻辑读 897 次,物理读 0 次,预读 0 次。
表 'Inpt_CtnOrderDetail'。扫描计数 0,逻辑读 0 次,物理读 0 次,预读 0 次。
表 'Inpt_TranCtnOrderDetail'。扫描计数 2,逻辑读 4 次,物理读 0 次,预读 0 次。
表 'Pub_Departments'。扫描计数 95,逻辑读 190 次,物理读 0 次,预读 0 次。
表 'Inpt_OrderMaster'。扫描计数 3,逻辑读 636 次,物理读 0 次,预读 0 次。
表 'Inpt_OrderDetail'。扫描计数 2,逻辑读 2 次,物理读 0 次,预读 0 次。
SQL Server 执行时间: 
  CPU 时间 = 31 毫秒,耗费时间 = 64 毫秒。

B:
(所影响的行数为 293 行)

表 'Pub_Tariff'。扫描计数 2341,逻辑读 5265 次,物理读 0 次,预读 0 次。
表 'Inpt_Wastebook'。扫描计数 2,逻辑读 466 次,物理读 0 次,预读 0 次。
表 'Pub_Medicines'。扫描计数 617,逻辑读 1631 次,物理读 0 次,预读 0 次。
表 'Inpt_SpecializedTrpDetail'。扫描计数 2,逻辑读 42952 次,物理读 0 次,预读 0 次。
表 'Inpt_SpecializedTrpMaster'。扫描计数 2,逻辑读 1086 次,物理读 0 次,预读 0 次。
表 'Inpt_TranCtnOrderMaster'。扫描计数 922,逻辑读 133898 次,物理读 0 次,预读 0 次。
表 'Inpt_TranCtnOrderDetail'。扫描计数 1,逻辑读 77 次,物理读 0 次,预读 0 次。
表 'Inpt_CtnOrderMaster'。扫描计数 244,逻辑读 31161 次,物理读 0 次,预读 0 次。
表 'Inpt_CtnOrderDetail'。扫描计数 2,逻辑读 15 次,物理读 0 次,预读 0 次。
表 'Pub_Departments'。扫描计数 6,逻辑读 10 次,物理读 0 次,预读 0 次。
表 'Inpt_OrderMaster'。扫描计数 12,逻辑读 120337 次,物理读 0 次,预读 0 次。
表 'Inpt_OrderDetail'。扫描计数 2,逻辑读 20 次,物理读 0 次,预读 0 次。
表 'Inpt_Registers'。扫描计数 1,逻辑读 5 次,物理读 0 次,预读 0 次。
表 'Inpt_Patients'。扫描计数 1,逻辑读 2 次,物理读 0 次,预读 0 次。

SQL Server 执行时间: 
  CPU 时间 = 7140 毫秒,耗费时间 = 16608 毫秒。


百思不得其解,有SQL高手指点一下吗?  


------解决方案--------------------
分别选中这两句SQL,按CTRL + L看看执行计划或许你就清楚了。
------解决方案--------------------
子查询
------解决方案--------------------
因为in 子查询,是返回 一个结果集,每次都返回一个结果集,反复查询,资源消耗大。
而第一个只返回一个值,只查询一次。
改成下面,还更快
SQL code
declare @s varchar(20)
  set @s='1001001'
  select * from 住院病人费用明细记录 where 
exists( select 病人ID from 住院病人登记记录 where 住院病人费用明细记录.病人ID=住院病人登记记录.病人ID and 住院号=@s)

------解决方案--------------------
探讨
因为in 子查询,是返回 一个结果集,每次都返回一个结果集,反复查询,资源消耗大。
而第一个只返回一个值,只查询一次。
改成下面,还更快

SQL code
declare @s varchar(20)
set @s='1001001'
select * from 住院病人费用明细记录 where 
exists( select 病人ID from 住院病人登记记录 whe……

------解决方案--------------------
B.declare @s varchar(20)
set @s='1001001'
select * from 住院病人费用明细记录 where 病人ID=
(select 病人ID from 住院病人登记记录 where 住院号=@s)
=================
将“住院病人登记记录”中的“ 病人ID”加上index就可以了,你肯定执行了table scan,所以很慢。
程序中处理,你不可能像A那样分两次去DB取值,这样更消耗资源。