SQL 调优,长时间运行的查询 + rownum
Posted
技术标签:
【中文标题】SQL 调优,长时间运行的查询 + rownum【英文标题】:SQL tuning, long running query + rownum 【发布时间】:2017-05-25 09:20:58 【问题描述】:我在数据库表中有数百万条记录,其中包含帐号、地址和更多列。我想要 100 行以 desc 顺序排序,我为此使用了 rownum,但是查询需要很长时间才能执行,因为它首先扫描整个表,使其按排序顺序然后应用 rownum。
最小化查询执行时间的解决方案是什么?
例如:
select *
from
(select
acc_no, address
from
customer
order by
acc_no desc)
where
ROWNUM <= 100;
【问题讨论】:
你在客户表上定义了索引吗? Sumit 说你应该有一个索引,我假设 acc_no 是唯一的?如果它不是你的主键,它至少应该包含在索引中 这适用于哪个 RDBMS?请添加标签以指定您使用的是mysql
、postgresql
、sql-server
、oracle
还是db2
- 或完全其他的东西。
是的,索引已定义,我有查询(连接到多个表)返回 30 万条记录,但在 UI 中我只想显示 100 条记录,但由于查询本身需要很长时间execute ,因此在将 rownum 应用于外部查询后,它需要相同的时间,对此的任何解决方案。 @marc_s : 是 oracle DBMS
【参考方案1】:
根据过去的经验,我发现 TOP 最适合这种情况。
此外,您应该始终选择您只需要的列,并避免使用全卡 (*)
SELECT TOP 100 [acc_no], [address] FROM [customer] ORDER BY [acc_no] DESC
关于 TOP、LIMIT 甚至 ROWNUM 的有用资源。
https://www.w3schools.com/sql/sql_top.asp【讨论】:
【参考方案2】:确保在 acc_no 列上使用索引。
-
如果 acc_no 上已存在索引,请通过验证查询执行计划来检查该索引是否在查询执行期间使用。
要创建新索引(如果不存在),请使用以下查询:
Create index idx1 on customer(acc_no); -- If acc_no is not unique
Create unique index idx1 on customer(acc_no); -- If acc_no is unique. Note: Unique index is faster.
-
如果在解释计划输出中看到“全表扫描”,则说明优化器未使用索引。
先尝试提示:
select /*+ index(idx1) */ * from
(select
acc_no, address
from
customer
order by
acc_no desc)
where
ROWNUM <= 100;
-
如果上面有提示的查询很快返回结果,那么你需要检查优化器为什么故意忽略你的索引。造成这种情况的一个可能原因是过时的统计数据。刷新统计信息。
希望这会有所帮助。
【讨论】:
【参考方案3】:考虑在内部查询/内联视图中获取您的主要帐号,以便您只对这 100 条客户记录执行联接。否则,您可能会在百万+行上执行所有联接,然后对百万+结果进行排序以获得前 100 名。这样的事情可能会奏效。
select .....
from customer
where customer.acc_no in (select acc_no from
(select inner_cust.acc_no
from customer inner_cust
order by inner_cust.acc_no desc
)
where rownum <= 100)
and ...
或者,如果您使用的是 12C,则可以使用 FETCH FIRST 100 ROWS ONLY
select .....
from customer
where customer.acc_no in (select inner_cust.acc_no
from customer inner_cust
order by inner_cust.acc_no desc
fetch first 100 rows only
)
and ...
【讨论】:
【参考方案4】:这将在 100 毫秒内给出结果,但请确保 ACC_NO 列上有索引。 ACC_NO+其他列也可以组合索引,但ACC_NO必须在索引的第一个位置。您必须在执行计划中看到“范围扫描”。不是“全表扫描”,也不是“跳过扫描”。您可能会在执行计划中看到嵌套循环(将从表中获取地址)。您可以通过为 ACC_NO、ADDRESS(按此顺序)创建组合索引来进一步提高速度。在这种情况下,Oracle 引擎根本不需要读取表,因为所有信息都包含在索引中。您可以在执行计划中进行比较。
select top 100 acc_no, address
from customer
order by acc_no desc
【讨论】:
我不确定,在这种情况下您的 SQL 是否正确,只需注意正确设置索引以上是关于SQL 调优,长时间运行的查询 + rownum的主要内容,如果未能解决你的问题,请参考以下文章
Spark SQL + Window + Streaming 问题 - 使用 Spark Streaming 运行时,Spark SQL 查询需要很长时间才能执行