ORACLE SQL 获取 Distincts 的方法是什么

Nic*_*cko 0 sql oracle oracle11g

我试图更好地理解 Oracle SQL 在执行代码时如何确定不同值。我希望它一次只对一列起作用,然后将所有重复项放在一边,然后仅在这些行上比较下一列。这将通过验证下一列是否有任何重复项来继续,并且每次只有继续具有重复项的行才会进入下一步。这准确吗?此外,是否有一种方法可以用来确定从哪一列开始?有些列很可能有重复项,而其他列可能是不应包含任何重复项的键(假设联接或联合上没有发生重复)。

Chr*_*xon 5

有两种基本方法:

  • 构建唯一值的哈希表
  • 在此过程中对数据进行排序和去重

散列往往更有效。

在以下情况下优先选择排序:

  • 查询有一个order by- 数据无论如何都必须排序,所以没有必要进行散列排序

  • 不同表达式上有一个索引 - 数据库可以遍历索引来查找唯一值。如果它是唯一索引,则也可以跳过重复数据删除步骤,因为保证值是唯一的。

优化器也可能考虑其他因素(例如不同值的预期数量、空值数量、总数据集大小等)。优化器何时选择哈希排序的确切细节可能因版本而异。

这里有些例子:

-- distinct a non-indexed column => hash
select distinct salary from hr.employees;

select * 
from   table ( dbms_xplan.display_cursor ( format => 'BASIC' ) );
/*
----------------------------------------
| Id  | Operation          | Name      |
----------------------------------------
|   0 | SELECT STATEMENT   |           |
|   1 |  HASH UNIQUE       |           |
|   2 |   TABLE ACCESS FULL| EMPLOYEES |
----------------------------------------
*/

-- order by & distinct => sort
select distinct salary from hr.employees
order  by salary;

select * 
from   table ( dbms_xplan.display_cursor ( format => 'BASIC' ) );
/*
----------------------------------------
| Id  | Operation          | Name      |
----------------------------------------
|   0 | SELECT STATEMENT   |           |
|   1 |  SORT UNIQUE       |           |
|   2 |   TABLE ACCESS FULL| EMPLOYEES |
----------------------------------------
*/

-- index on distinct column => sort
select distinct department_id from hr.employees;

select * 
from   table ( dbms_xplan.display_cursor ( format => 'BASIC' ) );
/*
------------------------------------------------
| Id  | Operation          | Name              |
------------------------------------------------
|   0 | SELECT STATEMENT   |                   |
|   1 |  SORT UNIQUE NOSORT|                   |
|   2 |   INDEX FULL SCAN  | EMP_DEPARTMENT_IX |
------------------------------------------------
*/

-- distinct of unique/primary index => no sort/hash needed! Just read the index
select distinct employee_id from hr.employees;

select * 
from   table ( dbms_xplan.display_cursor ( format => 'BASIC' ) );
/*
------------------------------------------
| Id  | Operation        | Name          |
------------------------------------------
|   0 | SELECT STATEMENT |               |
|   1 |  INDEX FULL SCAN | EMP_EMP_ID_PK |
------------------------------------------
*/
Run Code Online (Sandbox Code Playgroud)