事先申明下,我的DB环境是Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production,如果与作者环境不同而导致结论差异则另当别论。

该案例做了一个id为varchar类型的两种查询对比,我模拟了一下。

我是这样建表的:

create table tb_varchar2id(
id varchar2(20) primary key,
name nvarchar2(20),
sal number(5,0)
) insert into tb_varchar2id
select rownum,dbms_random.string('*',dbms_random.value(6,20)),dbms_random.value(1000,30000) from dual
connect by level<=2000000
order by dbms_random.random

原作中是320万,我机器受限只能弄200万,这个差别不影响作者的思路和我的结论。

建表完提交后,开始第一个查询并观察其执行计划:

SQL> select * from tb_varchar2id where id>='';
已用时间: 00: 00: 00.00 执行计划
----------------------------------------------------------
Plan hash value: 3377844066 -----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1006K| 45M| 3602 (2)| 00:00:44 |
|* 1 | TABLE ACCESS FULL| TB_VARCHAR2ID | 1006K| 45M| 3602 (2)| 00:00:44 |
----------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 1 - filter("ID">='') Note
-----
- dynamic sampling used for this statement (level=2)

这里走的也是全表扫描,cost是3602,作者那边不同的是8927.

再看封闭范围的查询及执行计划:

SQL> select * from tb_varchar2id where id between '' and '';
已用时间: 00: 00: 00.00 执行计划
----------------------------------------------------------
Plan hash value: 1409398992 ---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 104K| 4773K| 399 (0)| 00:00:05 |
| 1 | TABLE ACCESS BY INDEX ROWID| TB_VARCHAR2ID | 104K| 4773K| 399 (0)| 00:00:05 |
|* 2 | INDEX RANGE SCAN | SYS_C0011453 | 104K| | 357 (0)| 00:00:05 |
--------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("ID">='' AND "ID"<='') Note
-----
- dynamic sampling used for this statement (level=2)

这把走的是索引范围扫描,cost是399,原著中是5(作者加了索引SYS_C0025295)。

就本例而言,换了查询方式后cost从3602降到399,似乎有了数量级的提升,而原著中8927到5,更是令人瞠目结舌!

很多看官看到这里都要作者所云以为开放(>=)区间查询要次于封闭区间(between)查询了,还以为作者给出了一条可行的优化之路。

但是,下面两条SQL执行结果是不一样的。

select * from tb_varchar2id where id>='1900000';
select * from tb_varchar2id where id between '1900000' and '2000000';

让我们看看它们的数量:

SQL> set autotrace off;
SQL> select count(*) from tb_varchar2id where id>=''; COUNT(*)
----------
999995 已用时间: 00: 00: 00.21
SQL> select count(*) from tb_varchar2id where id between '' and ''; COUNT(*)
----------
111113 已用时间: 00: 00: 00.00

前者是将近一百万条,后者是十一万条,数据量有一个数量级的差距,cost自然也有一个数量级的差距。

为什么会这样?因为id是varchar2类型,不是number类型,上面SQL在搞字符串比较呢。

就比如运行select * from tb_varchar2id where id>='1900000' and rownum<20;

SQL> select * from tb_varchar2id where id>='' and rownum<20;

ID                   NAME                                            SAL
-------------------- ---------------------------------------- ----------
1900000 YQJQLHKTYVLSZX 12533
1900001 SPLMMLXO 18104
1900002 TYGGIMJCSIWOWUX 6383
1900003 SYYYNRXSL 15890
1900004 GEGQAG 9448
1900005 SFGBZMMPOSEVMNEHQ 20339
1900006 OMQGZZWVEPRWIMTYK 13421
1900007 PWHATEOVY 11135
1900008 TLBRFDWDCEMXFYUXYH 15930
1900009 ZUIQECXIRQXBTO 15961
190001 WKEAMSE 25082 ID NAME SAL
-------------------- ---------------------------------------- ----------
1900010 CMPQCVUBXSMBCMI 17296
1900011 QDPNUNBDXBKV 17393
1900012 OYQBIBRADGE 12009
1900013 VIRWDAKEE 18760
1900014 NQJYHGKREUKGENWH 28990
1900015 IKUUFL 7899
1900016 ACQDSR 1195
1900017 NXIECMAVNE 4208 已选择19行。

连190001都混迹其中,这不应该是符合两个SQL意图的记录。

所以,这是不同SQL在比较性能,这有意义吗?

作者一开头就出这么一个让人费解的地方,或是有些细节没有明写在书里,引起读者疑惑,有点不应该。

--2020年1月31日--

最新文章

  1. thinkphp3.2.3中U()方法和redirect()方法区别
  2. IOC框架整体介绍
  3. 针对BootStrap中tabs控件的美化和完善
  4. [JDBC-2] JDBC CURD
  5. vss报错Workgroup无法访问,您可能没有权限使用网络资源解决办法
  6. OD调试6—使未注册版软件的功能得以实现
  7. git 拉取远程分之到本地
  8. C#Redis字符串
  9. acm课程练习2--1005
  10. C语言中NULL的定义
  11. Davinci DM6446开发攻略——linux-2.6.18移植
  12. [Swift]LeetCode815. 公交路线 | Bus Routes
  13. 洛谷P4057
  14. 时间函数(1):time,ctime,gmtime,localtime
  15. CodeForces 371C Hamburgers(经典)【二分答案】
  16. LeetCode--No.001 Two Sum
  17. 撤销commit
  18. Tomcat的下载、安装、启动与关闭
  19. mybatis缓存(一,二级别)
  20. Python学习-36.Python中的字典解释

热门文章

  1. 使用免费证书安装 ipa 到真机
  2. 《Python测试开发技术栈—巴哥职场进化记》—软件测试工程师“兵器库”
  3. JAVA多线程之生产者 消费者模式 妈妈做面包案例
  4. Bytom侧链Vapor源码浅析-节点出块过程
  5. Codechef June Challenge 2020 Division 1 记录
  6. QT QMdiArea 添加背景或添加背景图片失效问题
  7. 打开终端自动source .bashrc文件
  8. LeetCode.516 最长回文子序列 详解
  9. Docker日常使用方式
  10. Javascript模块化编程(二):AMD规范 (转)