select 查询性能与主键、外键

select query performance Vs primary,foreign key

我已经将 table 结构(没有主键和外键约束)、数据、索引(所有索引)从一个模式复制到另一个模式。

在尝试 运行 具有多个连接的 select 查询(在新模式中)时,它比 运行 在旧模式中执行相同查询花费的时间长得多(有限制)。

遗漏的外键和主键约束是否是这种性能滞后的原因?

我在将对象从一个环境导入到另一个环境时遇到了类似的性能问题,然后我添加了缺少的约束,然后我可以看到性能有了很好的改进。 因此,我会请您添加约束,然后 运行 您的连接查询。

首先,主键和唯一键也是索引(即约束由索引支持),因此缺少主键或唯一键可能意味着缺少索引。

此外,如果有约束,优化器可以应用一些转换。例如,考虑这个查询(使用 Oracle HR 演示模式):

select count(*)
from   employees e
       join departments d on d.department_id = e.department_id;

执行计划:

--------------------------------------------------------------------------------------
| Id  | Operation        | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                   |     1 |     3 |     0   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE  |                   |     1 |     3 |            |          |
|*  2 |   INDEX FULL SCAN| EMP_DEPARTMENT_IX |   106 |   318 |     0   (0)| 00:00:01 |
--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("E"."DEPARTMENT_ID" IS NOT NULL)

注意没有对 departments 的引用。优化器知道 employees 中的 department_id 必须存在于 departments 中,因为有一个外键强制执行此操作,而且它只能在 departments 中出现一次,因为它是主要的钥匙。因此,不需要实际评估连接,因为它需要做的就是检查 e.department_id 是否不为空。由于该列上有一个索引,它可以将索引视为瘦 table,甚至不会触及 employees。 (如果 e.department_id 被定义为 not null,它甚至不需要那个过滤器。)

现在看看如果我们禁用约束会发生什么:

SQL> alter table employees disable constraint EMP_DEPT_FK;

Table altered.

SQL> select count(*)
  2  from   employees e
  3         join departments d on d.department_id = e.department_id;

  COUNT(*)
----------
       106

SQL> @xplan
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
Compatibility is set to 12.2.0.0.0

Plan hash value: 1475840611

-----------------------------------------------------------------------------------------
| Id  | Operation           | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |                   |     1 |     7 |     0   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE     |                   |     1 |     7 |            |          |
|   2 |   NESTED LOOPS      |                   |   106 |   742 |     0   (0)| 00:00:01 |
|   3 |    INDEX FULL SCAN  | EMP_DEPARTMENT_IX |   107 |   321 |     0   (0)| 00:00:01 |
|*  4 |    INDEX UNIQUE SCAN| DEPT_ID_PK        |     1 |     4 |     0   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   4 - access("D"."DEPARTMENT_ID"="E"."DEPARTMENT_ID")