事先申明下,我的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. js 自定义属性操作

    自定义属性操作     element.属性 获取内置属性值     element.getAttribute("属性") 我们自己添加的属性叫自定义属性     element. ...

  2. Javascript注意点

    Javascript注意点 在img标签中的src如果为相对路径, 但是在js获取的时候会转为全路径 候选框中, 在执行onclick之前, 会由于html的特征先设置checked属性 为a标签添加 ...

  3. Windows10上安装Linux子系统(WSL2,Ubuntu),配合Windows Terminal使用

    Linux 的 Windows 子系统可让开发人员按原样运行 GNU/Linux 环境 - 包括大多数命令行工具.实用工具和应用程序 - 且不会产生传统虚拟机或双启动设置开销. WSL 说白了安装Li ...

  4. java 异常二

    一 捕获异常try…catch…finally 捕获:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理 捕获异常格式: try { //需要被检测的语句. } catch(异 ...

  5. 钉钉H5微应用

    公司新项目要用到Vue+钉钉H5,在此记录一下免密登录: 引入插件: import * as dd from 'dingtalk-jsapi' import { login as loginUrl } ...

  6. Linux下安装Readis

    Redis的官方下载网址是:http://redis.io/download  (这里下载的是Linux版的Redis源码包) Redis服务器端的默认端口是6379. 首先我们先把整体的流程先书写下 ...

  7. Mac中的垃圾文件的清理

    一 前言 最近发现mac的存储空间不够了,看一下系统的存储空间如下图所示,这个其他占了160+G的存储空间,那么这个其他到底包含什么东西呢?在网上查了很久,找到一种比较认可的说法是这样的: 不同Mac ...

  8. Django context must be a dict ranther than Context

    1.1 错误描述 TypeError at /time/ context must be a dict rather than Context. Request Method: GET Request ...

  9. 浏览器自动化的一些体会8 HttpWebRequest的几个问题

    前面说过了,httpWebRequest的好处在于轻量,不需要界面,缺点在于无法执行javascript.这里再归纳一些问题. 1. 设置代理 1) httpWebRequest不支持https的代理 ...

  10. 前端vue2-org-tree实现精美组织架构图

    最近遇到开发组织架构的需求,与以往开发的组织架构不同,不光要展示人名,还要显示职务(或者子公司名称).对应的头像等,并且要考虑,如果用户未上传头像,需使用默认头像(男.女.中性),(⊙o⊙)…要尊重尊 ...