使用 rownum = 1 和 order by 编写 Oracle Select 语句的最佳方法

Posted

技术标签:

【中文标题】使用 rownum = 1 和 order by 编写 Oracle Select 语句的最佳方法【英文标题】:Best way to write Oracle Select Statement with rownum = 1 and order by 【发布时间】:2017-08-24 15:47:08 【问题描述】:

我有一个 oracle select 语句,但需要 1.58 秒才能获得我的 1 行,这对于这个单个查询来说很长时间 > 表包含大量数据

 select g.id
   from TBL1 g 
   left join TBL2 b on g.REF1= b.REF2 
  where b.id = 286 
    and ROWNUM = 1 
  order by g.id desc 

但是当我选择所有数据而不排序或限制时,它需要 0.027 !

实现这一目标的最佳方法是什么?

【问题讨论】:

没有 ORDER BY 子句的整个查询甚至可能给出 1000000 行,但您的客户端(我猜 - SQL-Developer 或类似的)仅显示前 50-100 行。它很快。但是,如果您使用ORDER BY,则 RDBMS 必须首先对所有 1000000 进行排序,然后选择最高/最低的 1 行。这必须需要一些时间。如果要优化此查询,请运行EXPLAIN PLAN FOR your_qury,然后运行SELECT * FROM table(DBMS_XPLAN.Display),并将最后一个查询的结果附加到问题中。这是分析性能问题的第一个基本步骤。 @Abu Yousef :Rownum 和 order by 子句不适合一个语句,你肯定需要在外部查询中使用你的 rownum,检查这个***.com/questions/9240192/… 已编辑:SQL 不是全部在一行时更容易阅读! @Abu Yousef :如果您要求从包含不同面额的篮子中随机挑选一枚硬币 1,2,3,4,5,6,7,8,9,10 会怎样?很简单。如果您要求从篮子中挑选最低面额的硬币怎么办。为此,您需要扫描所有硬币面额并得出结论 1 更小,同样的方式 oracle 无需订购即可进行操作,它挑选并提供随机数据。但是如果您要求 oracle 订购并获取最低的数据,则需要时间取决于表的大小。 @AbuYousef 现在不寻找性能,首先了解检索数据的基本原理,将结果与查询进行比较,您就可以了解我在做什么。关于性能,tbL1.id 上的索引可能会有所帮助,因为默认情况下索引按升序存储,请测试 【参考方案1】:

如果您使用的是 Oracle 12.1,则可以使用 Top-N 查询:

select g.id
   from TBL1 g 
   left join TBL2 b on g.REF1= b.REF2 
  where b.id = 286 
  order by g.id desc
FETCH FIRST 1 ROW ONLY

否则,您可以使用子查询获取第一行:

select * from (
  select g.id
     from TBL1 g 
     left join TBL2 b on g.REF1= b.REF2 
    where b.id = 286 
    order by g.id desc
) where ROWNUM = 1

这两种形式都允许 Oracle 使用 top-N 优化以避免在对结果进行排序时将整个结果集保留在 temp 中。

要进一步优化,您需要查看表、它们的索引和查询的解释计划。一些粗略的想法/猜测:

检查TBL2.id 是否有索引 考虑在TBL2 (id,REF2) 上建立索引 检查TBL1.REF1 是否有索引 考虑在TBL1 (REF1,id) 上建立索引

但是,在考虑上述内容之前,请确保您正在优化的查询实际上是您的应用程序将使用的查询。您在查询中硬编码了文字值 286 令人怀疑 - 也许这应该是一个绑定变量。

附:由于 b.id 上的 WHERE 子句,这不是外连接,因此 left 关键字是多余的。

【讨论】:

以上是关于使用 rownum = 1 和 order by 编写 Oracle Select 语句的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

oracle SQL语句中结合order by子句使用rownum

避坑,Oracle中rownum与order by的执行顺序

oracle 分页 有无order by情况不同吗

[技术分享]20171214_oracle_带rownum的查询语句查询出重复数据:原因是order by没有加主键

RESET SUM(AMT_FIELD) OVER(PARTITION BY UNIQUE FIELD ORDER BY ROWNUM)

row_number() over(partition by 列名1 order by 列名2 ) 实际应用