【问题标题】:Remove ORDER BY clause from PARTITION BY clause?从 PARTITION BY 子句中删除 ORDER BY 子句?
【发布时间】:2011-09-07 10:35:02
【问题描述】:

有没有办法可以减少下面内部查询的 OVER 部分中的“ORDER BY lro_pid”子句的影响?

SELECT *
  FROM (SELECT a.*, 
               Row_Number() over (PARTITION BY search_point_type 
                                      ORDER BY lro_pid) spt_rank
          FROM lro_search_point a
      ORDER BY spt_rank)
 WHERE spt_rank = 1;

我不想在分区中对这个结果进行排序,因为我想完全按不同的变量对其进行排序。 lro_pid 是一个索引列,但是就目前而言,这似乎仍然是一种资源浪费。 (也许有一种方法可以将排序限制在单行的范围内??希望根本不会花费时间/精力在分区内进行排序)

【问题讨论】:

  • +1,很有趣。我确实想知道在分区内进行排序是否真的要花很多钱。
  • 从@jonearles 的测试来看,我认为答案是肯定的。给定一个足够大的数据集,其中要分区的列是非索引的,这可能会产生很大的不同!感谢您的 cmets 和回答!

标签: sql oracle oracle10g oracle11g analytic-functions


【解决方案1】:

有几件事可以尝试:

你能举个例子吗? ORDER BY 'constant' 在 OVER 子句中?

如果不允许按常量排序,ORDER BY (lro_pid * 0) 怎么样?

我不是 Oracle 专家(MSSQL 更适合我) - 因此需要回答您的问题!

【讨论】:

  • +1,聪明!它似乎有效,即,如果我只是从表中发出选择并按“1”排序,结果似乎是无序的,并且似乎与没有排序的顺序相同。我不得不怀疑 order by 子句是否真的要花很多钱,如果有的话。计时测试已准备就绪!
  • @DCookie - 谢谢,我希望这些方法中的任何一种都能够被查询优化器“优化掉”。
【解决方案2】:

按照@Will A 的建议,在分析 ORDER BY 中使用常量似乎是最快的方法。 优化器仍然执行排序,但它比对列进行排序要快。 此外,您可能希望删除第二个 ORDER BY,或者至少将其移至外部查询。

下面是我的测试用例:

--Create table, index, and dummy data.
create table lro_search_point(search_point_type number, lro_pid number, column1 number
    ,column2 number, column3 number);
create index lro_search_point_idx on lro_search_point(lro_pid);
insert /*+ append */ into lro_search_point
select mod(level, 10), level, level, level, level from dual connect by level <= 100000;
commit;


--Original version.  Averages 0.53 seconds.
SELECT * FROM 
(
    SELECT a.*, Row_Number() over (PARTITION BY search_point_type ORDER BY lro_pid) spt_rank
    FROM lro_search_point a
    ORDER BY spt_rank
)
WHERE spt_rank=1;


--Sort by constant.  Averages 0.33 seconds.
--This query and the one above have the same explain plan, basically it's
--SELECT/VIEW/SORT ORDER BY/WINDOW SORT PUSHED RANK/TABLE ACCESS FULL.
SELECT * FROM 
(
    SELECT a.*, Row_Number() over (PARTITION BY search_point_type ORDER BY -1) spt_rank
    FROM lro_search_point a
    ORDER BY spt_rank
)
WHERE spt_rank=1;


--Remove the ORDER BY (or at least move it to the outer query).  Averages 0.27 seconds.
SELECT * FROM 
(
    SELECT a.*, Row_Number() over (PARTITION BY search_point_type ORDER BY -1) spt_rank
    FROM lro_search_point a
)
WHERE spt_rank=1;


--Replace analytic with aggregate functions, averages 0.28 seconds.
--This idea is the whole reason I did this, but turns out it's no faster.  *sigh*
--Plan is SELECT/SORT GROUP BY/TABLE ACCESS FULL.
--Note I'm using KEEP instead of just regular MIN.
--I assume that you want the values from the same row.
SELECT a.search_point_type
    ,min(lro_pid) keep (dense_rank first order by -1)
    ,min(column1) keep (dense_rank first order by -1)
    ,min(column2) keep (dense_rank first order by -1)
    ,min(column3) keep (dense_rank first order by -1)
FROM lro_search_point a
group by a.search_point_type;

【讨论】:

    【解决方案3】:

    要省略子句ORDER BY,您可以使用ORDER BY rownum。

    【讨论】:

      猜你喜欢
      • 2015-11-29
      • 2019-03-21
      • 1970-01-01
      • 2018-03-23
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多