事先申明下,我的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日--

对韩峰著《SQL优化最佳实践》P7 案例的质疑的更多相关文章

  1. sql优化最佳实践

    1.选择最有效率的表连接顺序 首先要明白一点就是SQL 的语法顺序和执行顺序是不一致的 SQL的语法顺序: select   [distinct] ....from ....[xxx  join][o ...

  2. SQL Server - 最佳实践 - 参数嗅探问题 转。

    文章来自:https://yq.aliyun.com/articles/61767 先说我的问题,最近某个存储过程,暂定名字:sp_a 总是执行超时,sp_a带有一个参数,暂定名为 para1 var ...

  3. 一触即发 App启动优化最佳实践

    一触即发 App启动优化最佳实践 本文在 DiyCode 和 CSDN个人博客 同时首发,关注作者的 DiyCode帐号 或者 作者微博 可第一时间收到新文章推送. 文中的很多图都是Google性能优 ...

  4. Web前端优化最佳实践及工具集锦

    Web前端优化最佳实践及工具集锦 发表于2013-09-23 19:47| 21315次阅读| 来源Googe & Yahoo| 118 条评论| 作者王果 编译 Web优化Google雅虎P ...

  5. paip.前端加载时间分析之道优化最佳实践

    paip.前端加载时间分析之道优化最佳实践 1.另存为 ,查看文件尺寸..和图片. 2.view the 另存为的htm静态的文件单个的加载,看时间...可以排除编程语言的问题and 数据库.. ## ...

  6. 【读书笔记】读《高性能网站建设指南》及《高性能网站建设进阶指南:Web开发者性能优化最佳实践》

    这两本书就一块儿搞了,大多数已经理解,简单做个标记.主要对自己不太了解的地方,做一些记录.   一.读<高性能网站建设指南> 0> 黄金性能法则:只有10%~20%的最终用户响应时间 ...

  7. [转] Web 前端优化最佳实践之 Mobile(iPhone) 篇

    原文链接:http://dbanotes.net/web/best_practices_for_speeding_up_your_web_site_server_mobile.html Web 前端优 ...

  8. 经典的性能优化最佳实践 web性能权威指南 读书笔记

    web性能权威指南 page 203 经典的性能优化最佳实践 无论什么网络,也不管所用网络协议是什么版本,所有应用都应该致力于消除或减 少不必要的网络延迟,将需要传输的数据压缩至最少.这两条标准是经典 ...

  9. 史上最全存储引擎、索引使用及SQL优化的实践

    史上最全存储引擎.索引使用及SQL优化的实践 1 MySQL的体系结构概述 2. 存储引擎 2.1 存储引擎概述 2.2 各种存储引擎特性 2.2.1 InnoDB 2.2.2 MyISAM 3. 优 ...

随机推荐

  1. gotoblas,mpich,hpl,hpcg的安装

    gotoblas的安装 mpich 安装 tar zxvf mpich-3.2.1.tar.gz cd mpich-3.2 ./configure --prefix=/usr/local/mpich( ...

  2. 07 CentOS简单命令与XShell简单使用

    关机 poweroff 重启 init 6 查看ip地址 ifconfig 查看当前目录下的文件与目录 ls ll 判断命令是内部还是外部的类型 type ifconfig 通过file /sbin/ ...

  3. C#LeetCode刷题-随机数

    随机数篇 # 题名 刷题 通过率 难度 470 用 Rand7() 实现 Rand10()   34.4% 中等 478 在圆内随机生成点   22.8% 中等 497 非重叠矩形中的随机点   22 ...

  4. MySQL查看正在执行的SQL进程

    查看正在执行的SQL进程: show processlist; 查出来之后, 可以使用下面的命令终止SQL进程: kill ${进程ID}

  5. 01@-tornado

    import tornado.web ''' tornado的基础web框架模块 ''' import tornado.ioloop ''' tornado的核心IO循环模块 封装了Linux的epo ...

  6. Linux 查网关和dns命令

    一,查看网关(缺省路由)方法: 1.route -n 或netstat -rn2.ip route show  二, 查看DNS: nslookup www.baidu.com

  7. idea生成SpringBoot项目后再次调出依赖

    插眼 https://www.cnblogs.com/cosmos-wong/p/12908580.html

  8. Centos7查看端口占用

    (1)netstat -lnp|grep 50090 如果提示没有netstat命令,可需要安装:yum -y install net-tools (2) lsof -i:50090 参考链接:lin ...

  9. JavaScript学习系列博客_14_JavaScript中对象的基本操作

    对象的基本操作 - 创建对象 - 方式一:使用new关键字调用的函数,是构造函数(constructor),构造函数是专门用来创建对象的函数. var obj = new Object(); - 方式 ...

  10. 第3章 Hive数据类型

    第3章 Hive数据类型 3.1 基本数据类型 对于Hive的String类型相当于数据库的varchar类型,该类型是一个可变的字符串,不过它不能声明其中最多能存储多少个字符,理论上它可以存储2GB ...