事先申明下,我的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. LibSvm流程及java代码测试

    使用libSvm实现文本分类的基本过程,此文参考 使用libsvm实现文本分类 对前期数据准备及后续的分类测试进行了验证,同时对文中作者的分词组件修改成hanLP分词,对数字进行过滤,仅保留长度大于1 ...

  2. Java中编写代码出现异常,如何抛出异常,如何捕获异常

    异常的产生过程解析 先运行下面的程序,程序会产生一个数组索引越界异常ArrayIndexOfBoundsException.我们通过图解来解析下异常产生的过程. 工具类 class ArrayTool ...

  3. C#LeetCode刷题之#326-3的幂(Power of Three)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3867 访问. 给定一个整数,写一个函数来判断它是否是 3 的幂次 ...

  4. Vue element-ui el-table阻止行选事件

    我们经常会在某个table末尾加上操作列来放置button来处理跳转和其他的逻辑 那么当点击button的时候同样也会执行在el-table 设置的 @row-click="handleRo ...

  5. for语句——猜数字

    #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib. ...

  6. 理解RESTful原理

    如何给老婆解释什么是RESTful 老婆经常喜欢翻看我订阅的技术杂志,她总能从她的视角提出很多有趣的问题. 一个悠闲的周日下午,她午觉醒来,又习惯性的抓起这个月的杂志,饶有兴趣地看了起来. 果不其然, ...

  7. fatal error: glib.h: No such file or directory

    在学习BLE bluez的时候,做了一个测试程序,看到gatttool.c下面有一个glib解析命令行的功能,想移植到自己的程序接口中,但是添加了#include <glib.h>后,出现 ...

  8. 第4章 SparkSQL数据源

    第4章 SparkSQL数据源 4.1 通用加载/保存方法 4.1.1 手动指定选项 Spark SQL的DataFrame接口支持多种数据源的操作.一个DataFrame可以进行RDDs方式的操作, ...

  9. 【接口自动化】Python+Requests接口自动化测试框架搭建【三】

    经过上两篇文章的讲解,我们已经完成接口自动化的基础框架,现在开始根据实际项目丰满起来. 在PyCharm中新建项目,项目工程结构如下: config:配置文件夹,可以将一些全局变量放于配置文件中,方便 ...

  10. linux 修改 mac

    ifconfig eth0 hw ether fa::3d:c3:: 或 ip link set dev eth0 address fa::3d:c3::