使用 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的执行顺序
[技术分享]20171214_oracle_带rownum的查询语句查询出重复数据:原因是order by没有加主键
RESET SUM(AMT_FIELD) OVER(PARTITION BY UNIQUE FIELD ORDER BY ROWNUM)