我的编程空间,编程开发者的网络收藏夹
学习永远不晚

DISTICT的一次质疑

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

DISTICT的一次质疑

一直以来DISTINCT的用法都为DBA所知,就是用来滤重。我们也没有必要质疑DISTINCT的滤重准确性。

但今天突然不知道怎么想的,就想质疑一下。DISTINCT真的能保证过滤的对象没有重复记录吗?

SQL> create table test_distinct as select rownum id from all_objects where rownum < 50000;
insert into test_distinct select rownum id from all_objects where rownum < 50000;

这表中有重复的数据,数据插入顺序1~4999,然后再重复一次

SQL> select count(id) from (select distinct id from test_distinct) group by id having count(id) > 1;
no rows selected

可以看到,通过这条语句发现确实没有重复的行。那么进一步思考如果不用distinct如何实现这个效果呢。我想起了ROWID这个东西,以下两句的效果相同。

select count(distinct phoneno) from CUSTPHONE

select count(phoneno) from CUSTPHONE where rowid in( select min(rowid) from CUSTPHONE group by phoneno)

我想了解一下DISTINCT语句实际在Oracle中是如何操作的,通过10046事件和tkprof工具获取跟踪的信息。

SQL ID: 8vtyapcbqkbwf
Plan Hash: 2372476266
select distinct id
from
 test_distinct where rownum < 100

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.02       0.02          0        138          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        8      0.00       0.00          0          4          0          99
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       10      0.02       0.02          0        142          0          99
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Rows     Row Source Operation
-------  ---------------------------------------------------
     99  HASH UNIQUE (cr=4 pr=0 pw=0 time=0 us cost=528 size=1287 card=99)
     99   COUNT STOPKEY (cr=4 pr=0 pw=0 time=196 us)
     99    TABLE ACCESS FULL TEST_DISTINCT (cr=4 pr=0 pw=0 time=98 us cost=44 size=1318174 card=101398)

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       8        0.00          0.00
  asynch descriptor resize                        2        0.00          0.00
  SQL*Net message from client                     8       59.43         59.43

可以看到执行计划中DISINCT是通过HASH UNIQUE算法来实现的。同时ROWNUM虚列使用的是COUNT算法,STOPKEY说明我给ROWNUM虚列加了限定条件100,当到达这个限定条件时,该语句查询结束。

那么到这我该怎么理解HASH UNIQUE算法的目的呢?我在网上查看了相关信息,发现真有人做了实验实验帮助我们加上对该算法的印象。在10G2R以前,Oracle对DISTINCT使用的是sort unique这种操作方式因为涉及到排序,是非常影响语句的执行效率的。因此10G2R之后的版本,Oracle改进了算法。

SQL> select distinct id from test_distinct where rownum < 100;
99 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 2372476266
---------------------------------------------------------------------------------------------
| Id  | Operation           | Name          | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |               |    99 |  1287 |       |   528   (1)| 00:00:07 |
|   1 |  HASH UNIQUE        |               |    99 |  1287 |  2000K|   528   (1)| 00:00:07 |
|*  2 |   COUNT STOPKEY     |               |       |       |       |            |          |
|   3 |    TABLE ACCESS FULL| TEST_DISTINCT |   101K|  1287K|       |    44   (3)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(ROWNUM<100)
Note
-----
   - dynamic sampling used for this statement (level=2)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          4  consistent gets
          8  physical reads
          0  redo size
       2134  bytes sent via SQL*Net to client
        589  bytes received via SQL*Net from client
          8  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         99  rows processed

SQL> alter system flush buffer_cache

SQL> select id from test_distinct where rownum < 100 group by id;
99 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 521476922
-------------------------------------------------------------------------------------
| Id  | Operation           | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |               |    99 |  1287 |    47   (9)| 00:00:01 |
|   1 |  HASH GROUP BY      |               |    99 |  1287 |    47   (9)| 00:00:01 |
|*  2 |   COUNT STOPKEY     |               |       |       |            |          |
|   3 |    TABLE ACCESS FULL| TEST_DISTINCT |   101K|  1287K|    44   (3)| 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(ROWNUM<100)
Note
-----
   - dynamic sampling used for this statement (level=2)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          4  consistent gets
          8  physical reads
          0  redo size
       2134  bytes sent via SQL*Net to client
        589  bytes received via SQL*Net from client
          8  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         99  rows processed

通过网上这组实验可以看到DISTINCT和GROUP BY分别使用了HASH UNIQUE和HASH GROUP BY算法。而两者执行效果和结果都相同。基于规则的DISTINCT和GROUP BY的查询的执行计划如下

SQL> select  distinct id from test_distinct where rownum < 100;
99 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 3449293992
---------------------------------------------
| Id  | Operation           | Name          |
---------------------------------------------
|   0 | SELECT STATEMENT    |               |
|   1 |  SORT UNIQUE        |               |
|*  2 |   COUNT STOPKEY     |               |
|   3 |    TABLE ACCESS FULL| TEST_DISTINCT |
---------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(ROWNUM<100)
Note
-----
   - rule based optimizer used (consider using cbo)

Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          4  consistent gets
          8  physical reads
          0  redo size
       2134  bytes sent via SQL*Net to client
        589  bytes received via SQL*Net from client
          8  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
         99  rows processed

 
SQL> select  id from test_distinct where rownum < 100 group by id;
99 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 351786816
---------------------------------------------
| Id  | Operation           | Name          |
---------------------------------------------
|   0 | SELECT STATEMENT    |               |
|   1 |  SORT GROUP BY      |               |
|*  2 |   COUNT STOPKEY     |               |
|   3 |    TABLE ACCESS FULL| TEST_DISTINCT |
---------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(ROWNUM<100)
Note
-----
   - rule based optimizer used (consider using cbo)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          4  consistent gets
          8  physical reads
          0  redo size
       2134  bytes sent via SQL*Net to client
        589  bytes received via SQL*Net from client
          8  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
         99  rows processed

因为表的数据量教啥,基于rule的算法和通过hash的算法区别并不明显。但重点在于了解Oracle的不同算法的可能。

另外,ORACLE除了提供DISTINCT以外,还提供了UNIQUE来过滤重复的数据。官方文档给出的解释。

http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_10002.htm#SQLRF55272

DISTINCT | UNIQUE

Specify DISTINCT or UNIQUE if you want the database to return only one copy of each set of duplicate rows selected. These two keywords are synonymous. Duplicate rows are those with matching values for each expression in the select list.

到这里我已经理解了DISTINCT的作用,同时还学习了其它新的知识。非常棒!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

DISTICT的一次质疑

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

解读C#中ReadString的一些小疑惑

这篇文章主要介绍了关于C#中ReadString的一些小疑惑,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-01-28

C++模板编程的疑点逐一化解

c++++ 模板编程消除疑点:编译器通过类型推断规则推断模板参数;constexpr 关键字处理依赖于模板参数的常量;模板特化提供针对特定参数的实现;递归模板使用 enable_if 辅助类型检查。实战案例展示其阶乘计算和快速排序等功能。C
C++模板编程的疑点逐一化解
2024-05-21

Scrapy:python3下的第一次运

1,引言《Scrapy的架构初探》一文讲解了Scrapy的架构,本文就实际来安装运行一下Scrapy爬虫。本文以官网的tutorial作为例子,完整的代码可以在github上下载。2,运行环境配置本次测试的环境是:Windows10, Py
2023-01-31

聊一聊关于php源码中refcount的疑问

这篇文章主要给大家介绍了关于对php源码中refcount的相关疑问,文中通过实例代码介绍的非常详细,对大家的学习或工作具有一定的参考学习价值,需要的朋友可以参考下
2022-11-13

记一次goagent的设置

设置GoAgent代理服务器的步骤如下:1. 下载并安装GoAgent客户端。可以在GoAgent官方网站或者GitHub上找到最新的GoAgent客户端并下载安装。2. 解压缩GoAgent客户端,并打开client目录。3. 在clie
2023-09-21

书写高质量SQL的一些建议

select * from employee; 正例子: selectid,namefrom employee; 理由: 只取需要的字段,节省资源、减少网络开销。 select * 进行查询时,很可能就不会使用到覆盖索引了,就会造成回表查询。
书写高质量SQL的一些建议
2017-02-17

如何确定 PHP foreach 循环中的第一次和最后一次迭代

PHP foreach() 循环用于遍历数组中的每个元素。在本文中,我们将来学习如何使用 foreach() 循环以及如何获取数组的第一项和最后一项元素。PHP foreach() 语法foreach() 循环主要用于遍历数组的每个值。fo
如何确定 PHP foreach 循环中的第一次和最后一次迭代
2024-02-27

记一次CurrentDirectory导致的问题

在编程中,CurrentDirectory是一个表示当前工作目录的属性。它指示了程序在运行时所在的目录。一次由CurrentDirectory导致的问题是,程序无法找到所需的文件或目录。这可能是因为程序在不正确的目录下运行,或者因为Curr
2023-09-15

记一次MySQL的优化案例

一 背景 有赞的每个OLTP数据库实例上会设置一个sql-killer进程用于kill 掉执行时间超过一定阈值的sql。下午开发接收到sql被kill的报错,一起帮助开发排查,本文介绍该案例。 二 场景分析 表结构:CREAT
2022-05-16

安装Mysql时可能会遇到的一些疑难杂症

问题一: 在安装时候输入 net start mysql 时候报错为: net不是内部或外部命令也不是可运行。 解决方法: 环境变量的问题: 首先确定C:\Windows\System32下有net.exe。 在一下中 我的电脑?>属性?>
2022-05-26

软考一年考两次的科目一样吗

针对软考一年考两次的科目一样吗?软考一年考两次的科目哪些?的问题,希赛小编将软考考试科目的相关内容整理如下:(一)软考一年考两次的科目基本一样初级资格:信息处理技术员、网络管理员、程序员。中级资格:软件设计师、网络工程师、信息系统监理师、系统集成项目管理工程师。高级资格:信息系统项目管理师。2024年软考考试改革,高项
软考一年考两次的科目一样吗
2024-04-02

编程热搜

目录