查询一组数据,是尽可能的减少查询次数,使用少量的查询语句快呢?还是每个数据单独对应查询语句好?
大家看到上面的问题后,也许很快就有了自己的结论。
比如:求一类案件不同结论的数量各是多少?很多同学都会用到以下查询。
select
案件结论, count(*)
from
案件表
group by
案件结论
这样不管案件有多少种结论都能用上面的查询一次完成,而且速度是理想的。那么是不是所有的查询都是尽可能的精简呢?
下面的例子是从一个表上取某字段的最大值和最小值。
先别急下结论,我们通过Sybase ASE 做个实验,看看实际的情况吧。
测试
测试环境
测试表
|
K_ZNXT..B_STBD_XS
|
数据量
|
120184
|
索引
|
对字段 ZXXQ
|
说明:计划任务及IO读取只列出了关键部分。
有索引的情况
一条语句读取
select max(ZXXQ), min(ZXXQ) from K_ZNXT..B_STBD_XS
FROM TABLE
K_ZNXT..B_STBD_XS
Nested iteration.
Index : I_STBD_XS_ZXXQ
Forward scan.
Positioning at index start.
logical reads: (regular=1766 apf=0 total=1766)
physical reads: (regular=0 apf=0 total=0)
分两次读取
select max(ZXXQ) from K_ZNXT..B_STBD_XS
FROM TABLE
K_ZNXT..B_STBD_XS
Nested iteration.
Index : I_STBD_XS_ZXXQ
Backward scan.
Positioning at index end.
Scanning only up to the first qualifying row.
logical reads: (regular=3 apf=0 total=3)
physical reads: (regular=0 apf=0 total=0), apf IOs used=0
select min(ZXXQ) from K_ZNXT..B_STBD_XS
FROM TABLE
K_ZNXT..B_STBD_XS
Nested iteration.
Index : I_STBD_XS_ZXXQ
Forward scan.
Positioning at index start.
Scanning only up to the first qualifying row.
logical reads: (regular=723 apf=0 total=723)
physical reads: (regular=0 apf=0 total=0), apf IOs used=0
结论说明
比较项目
|
一句读取
|
两句读取
|
扫描方式
|
索引扫描
|
索引扫描
|
扫描方向
|
往前扫描
|
往前扫描 + 往后扫描
|
扫描条数
|
全部扫描
|
正序第一条 + 倒序第一条
|
IO
逻辑读
|
1766
|
3 + 723
|
IO
物理读
|
0
|
0
|
从数据上来看“两句读取”要用到的资源少一些,应该会执行快一些。
从实验的具体结果来看也是如此。
当数据都已加载到内存中,即IO物理读为0时,从执行时间来看差异性不大。
当数据都在磁盘中,会先把数据从磁盘加载到内存,这时再来看执行时间,差异性就明显了。
无索引的情况
一条语句读取
select max(ZXXQ), min(ZXXQ) from K_ZNXT..B_STBD_XS
FROM TABLE
K_ZNXT..B_STBD_XS
Nested iteration.
Table Scan.
Forward scan.
Positioning at start of table.
logical reads: (regular=7395 apf=0 total=7395)
physical reads: (regular=0 apf=0 total=0)
分两次读取
select min(ZXXQ) from K_ZNXT..B_STBD_XS
FROM TABLE
K_ZNXT..B_STBD_XS
Nested iteration.
Table Scan.
Forward scan.
Positioning at start of table.
logical reads: (regular=7395 apf=0 total=7395)
physical reads: (regular=0 apf=0 total=0)
select max(ZXXQ) from K_ZNXT..B_STBD_XS
FROM TABLE
K_ZNXT..B_STBD_XS
Nested iteration.
Table Scan.
Forward scan.
Positioning at start of table.
logical reads: (regular=7395 apf=0 total=7395)
physical reads: (regular=0 apf=0 total=0)
结论说明
比较项目
|
一句读取
|
两句读取
|
扫描方式
|
全表扫描
|
全表扫描
|
扫描方向
|
往前扫描
|
往前扫描 + 往前扫描
|
扫描条数
|
全部扫描
|
全部扫描 + 全部扫描
|
IO
逻辑读
|
7395
|
7395
+ 7395
|
IO
物理读
|
0
|
0
|
没有索引的情况下,全表扫描需要的资源陡然增加。每次查询都会用到全表扫描,结论自然也就显而易见了。
总结
执行SQL速度快慢得靠分析查询计划和IO读取的数据来说话。
在其他不同的条件下,同样的SQL也有不同的查询计划。
在时间允许的情况下,需要对SQL逐条分析,使其达到最优。
Oracle
中也有类似的情况,这里不再多举例子了。有兴趣的同学自己再试试吧。
附录
控制Session查询的输出
命令
|
说明
|
set statistics time on
|
输出执行时间
|
set statistics io on
|
输出IO量
|
set showplan on
|
输出计划任务
|
set noexec on
|
不具体执行SQL
|