按性能问题排序的 Oracle 查询

Posted

技术标签:

【中文标题】按性能问题排序的 Oracle 查询【英文标题】:Oracle query with order by perfomance issue 【发布时间】:2017-07-12 21:40:11 【问题描述】:

我的查询很复杂:

select * from (
select * from tbl_user ...
where ...
and date_created between :date_from and :today
...
order by date_created desc
) where rownum <=50;

由于 where 子句,当前查询速度足够快(仅在今天前 3 个月,date_from = 今天 - 90 天)。

我必须删除此子句,但它会导致性能下降。 如果先通过`

计算date_from会怎样
SELECT MIN(date_created) where...

然后将此值插入到主查询中?数据集将是相同的。它会提高性能吗?是否有意义? 任何人都可以对优化有任何假设吗?

【问题讨论】:

威尔,目前你的问题很难理解。请编辑您的帖子以更好地说明您的问题并包含您的架构和完整查询。如果您不提供此类内容,我们将无法完全帮助您优化您的解决方案。 索引了哪些列,我们在这里处理了多少行?您是否还检查了解释计划和/或自动跟踪以获取有关执行计划的信息? 限制子句(仅查找最近的 50 行)非常有用 - 即使您包括所有数据,而不仅仅是最近三个月,您也不会看到性能大幅下降。这是因为优化器看到了外部查询where 子句并且它没有对内部查询中的所有行进行排序——它只查找date_created 的最高50 个值。你有date_created 的索引吗?这应该很有帮助。 对 date_created 子集的评论:看执行计划,因为写的 SQL 需要隐式类型转换;如果 oracle 对列执行此操作,那么即使它有索引,也不会使用它。要绕过隐式类型转换,请在输入字符串周围显式使用 to_date 函数。 【参考方案1】:

使用order by 操作当然会导致查询需要更长的时间才能返回。话虽如此,在数据库中排序几乎总是比在应用程序逻辑中排序更快。

如果没有完整的查询和架构信息,很难真正优化,但我会尝试对我来说最明显的东西。

转换为 Rank()

如果您使用带窗口的rank() 函数,您的查询可能会更有效。我还将它转换为使用common table expression(又名CTE)。这不会提高性能,但会更容易阅读。

with cte as (
  select 
    * 
    , rank() over (
      partition by
        -- insert what fields differentiate your rows here
        -- unlike a group by clause, this doesn't need to be
        -- every field
      order by
        date_created desc
    )
  from 
    tbl_user 
    ...
  where 
    ...
    and date_created between :date_from and :today
)
select 
  * 
from 
  cte
where
  rk <= 50

索引

    如果date_created 未编入索引,则可能应该编入索引。 查看您的自动跟踪结果。找出哪些过滤器的成本最高。这些可能是未编入索引的,也许应该是。

如果您发布您的架构,我很乐意提出更好的建议。

【讨论】:

为什么rank() 会使查询更快?我不相信——你有这方面的文件或理论论证吗? rank() 中的 ORDER BY 子句与 OP 原始查询中的单独 ORDER BY 子句的作用相同。在这两种情况下,无论是使用单独的order by 子句还是rank(),限制性where 子句(rownum &lt;= 50rnk &lt;= 50)都将允许优化器重写,以便仅识别“第一”50 行,而不是订购整套。 此外,如果可以打成平手,正确使用的函数是row_number(),而不是rank() 对 date_created 子集的评论:看执行计划,因为写的 SQL 需要隐式类型转换;如果 oracle 在列上执行此操作,那么即使它有索引,也不会被使用。要绕过隐式类型转换,请在输入字符串周围显式使用 to_date 函数。 @RogerCornejo 不。假设将日期传递给绑定参数就可以了。 @Jacobm001 我并不是说优化器会使用隐式类型转换,而是我建议检查(而不是假设)它。来自执行计划(或 SQL 调优顾问)的详细信息应该告诉您哪些谓词用于访问(即正在使用的索引)或过滤器(只是数据子集)。

以上是关于按性能问题排序的 Oracle 查询的主要内容,如果未能解决你的问题,请参考以下文章

使用地理位置按距离排序提高性能

详解Oracle partition分区表

如何检查oracle数据库性能

超过 500 万条记录的 MongoDB 查询性能

带有子查询的 Oracle 更新 - 性能问题

(原创)性能测试中,Oracle服务器定位CPU使用率高的瓶颈(SQL)