从 PARTITION BY 子句中删除 ORDER BY 子句?

发布于 2024-11-13 22:17:30 字数 444 浏览 8 评论 0原文

有没有办法减少下面内部查询的 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 是一个索引列,但目前看来这仍然是浪费资源。 (也许有一种方法可以将排序限制在单行的范围内?希望根本不会花费时间/精力在分区内进行排序)

Is there a way I can reduce the impact of the 'ORDER BY lro_pid' clause in the OVER portion of the inner query below?

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;

I don't care to order this result within the partition since I want to order it by a different variable entirely. lro_pid is an indexed column, but this still seems like a waste of resources as it currently stands. (Perhaps there is a way to limit the ordering to a range of a single row?? Hopefully no time/energy would be spent on sorting within the partition at all)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜血缘 2024-11-20 22:17:30

有几点需要尝试:

您可以在 OVER 子句中使用 ORDER BY 'constant' 吗?

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

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

A couple of things to try:

Can you e.g. ORDER BY 'constant' in the OVER clause?

If ordering by a constant is not permitted, how about ORDER BY (lro_pid * 0)?

I'm not an Oracle expert (MSSQL is more my thing) - hence questions to answer your question!

∝单色的世界 2024-11-20 22:17:30

在分析 ORDER BY 中使用常量(如 @Will A 建议)似乎是最快的方法。
优化器仍然执行排序,但比对列进行排序要快。
另外,您可能想要删除第二个 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;

Using a constant in the analytic ORDER BY as @Will A suggested appears to be the fastest method.
The optimizer still performs a sort, but it's faster than sorting a column.
Also, you probably want to remove the second ORDER BY, or at least move it to the outer query.

Below is my test case:

--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;
遗弃M 2024-11-20 22:17:30

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

To obmit the clause ORDER BY you could use ORDER BY rownum.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文