oracle order by 运行速度非常慢

标签 oracle hibernate sql-order-by sql-optimization

我正在做这样的查询,需要 6 秒才能完成:

select * 
from ( select aaa."ID" 
      from "aaa"  
      where aaa."DELETED" is null 
      order by aaa."CREATED" desc ) 
where rownum <= 15;

我的表中有大约 160 万条记录,我尝试向已删除列和已创建列添加单独的索引,我尝试添加包含已创建和已删除列的索引,我已尝试创建相同的索引以不同的顺序。似乎没有任何帮助。我该怎么做才能加快速度?

我无法更改查询,因为它是由 hibernate 生成的

编辑: 即使没有 aaa."DELETED"is null 查询运行速度也很慢。

编辑 2: Query plan

编辑 3: 添加我的索引定义。老实说,我不知道这些数字中的大多数是什么意思,我正在使用 sqldeveloper 创建索引。甚至不知道每个索引都有这么多配置选项,我现在将查看文档。

CREATE INDEX "aaa"."aaa_CREATED_ASC" ON "aaa"."aaa"
  (
    "CREATED"
  )
  PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE
  (
    INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
  )
  TABLESPACE "SYSTEM" ;
CREATE INDEX "aaa"."aaa_CREATED_DESC" ON "aaa"."aaa"
  (
    "CREATED" DESC
  )
  PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE
  (
    INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
  )
  TABLESPACE "SYSTEM" ;

最佳答案

您需要了解 Oracle 如何访问数据库中的记录。索引读取是一种操作,表读取是另一种操作。因此,从表中检索一条索引记录至少需要两次读取。

您的查询使用三条信息:

  • DELETED 列(限制条件)
  • CREATED 列(排序标准)
  • ID(结果集)

Oracle 不索引 NULL 值,因此 DELETED 上的单列索引对您没有帮助。那是全表扫描,根本不比没有索引好。

CREATED 上的索引更好,因为访问路径将变为:

INDEX FULL SCAN DESCENDING

也就是说,它开始于 trhe 索引中的最新日期并向后工作。但是,查询仍需要读取表以查找 ID 和 DELETED 值。这可能是很多表读取,具体取决于 DELETED 为空的频率。

现在,(CREATED, DELETED) in that order 上的复合索引应该更有用,因为 Oracle 现在将索引 DELETED< 中的 NULL/列。 Oracle 可以使用索引来确保它只查找表记录以获取 ID 值。这将是 15 次表读取。

最后,您可以在 (CREATED, DELETED, ID) 上构建复合索引,并从索引中为整个查询提供服务。这是迄今为止最快的选择。

然后您只需要确定性能优势是否可以证明维护索引的开销是合理的。就其值(value)而言,维护复合索引的成本只增加了维护单列索引的成本的一小部分。


顺便说一句,像这样可怕的查询是使用逻辑删除是一个坏主意的原因之一。物理删除您的记录,并在需要时使用日志表检索表的历史状态。

关于oracle order by 运行速度非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8051174/

相关文章:

c# - Oracle NUMBER(20)对应的c#类型?

sql - partition by/order by 是否暗示查询中的排序?

java - 为什么我的 hibernate join 只返回一张表的查询?

jquery - 当我使用 order by desc 和 join 查询时,为什么它非常慢?

mysql 更新查询 : add a table column with values

java - JDBC + PL/SQL = 这么简单,还是有陷阱?

java - 如果数据库(oracle)中没有记录,如何使用 spring jpa 与日期列结合显示零作为计数?

sql - Oracle 如果不存在则插入

java - hibernate 获取懒惰: Initialize() or HQL

java - Hibernate 搜索索引单个租户