【问题标题】:Oracle SQL efficient query on Partitioned Table: "order by case"Oracle SQL对分区表的高效查询:“按大小写”
【发布时间】:2014-01-14 21:04:06
【问题描述】:

我得到一个包含大约 1000 亿条记录的表,该表在键 date_insert 上分区。

MY_BIG_TABLE

  • id NUMERIC 二级索引
  • date_insert DATE 主索引
  • date_fact DATE 二级索引
  • 数据 BLOB

输入:

  • :date_input1
  • :date_input2
  • :date_input3
  • :id

注意::date_input1 < :date_input2

我想要

  1. IF date_fact < :date_input_1 按 date_fact DESC 排序的第一行
  2. ELSE IF date_fact < :date_input_2 按 date_fact ASC 排序的第一行
  3. ELSE最新的

查询原型应该是:

SELECT date_insert, date_fact, data (

        SELECT
            date_insert, 
            date_fact,
            CASE 
               WHEN (date_fact < :date_input_1 AND id= :id) : 2
               WHEN (date_fact < :date_input_2 AND id= :id) : 1
               ELSE : 0  
            check,

            CASE 
               WHEN (date_fact < :date_input_1 AND id= :id) : NULL
               WHEN (date_fact < :date_input_2 AND id= :id) : data
               ELSE : NULL  
            data

        FROM MY_BIG_TABLE
        WHERE date_insert > :date_input3   
        order by check, DECODE(check, 1, date_fact) ASC,
                        date_fact DESC 

) WHERE ROWNUM <2

我需要做这项艰苦的工作以避免过多地访问此表。 有什么建议可以完全重建查询以使其更简单、更容易吗?

【问题讨论】:

  • 您的查询没有过滤器?对吗?
  • 是的,谢谢(查询是真实查询的原型)...刚刚编辑...对不起
  • 好吧,我不知道您的要求,但是,您是否真的需要将字段 data 设为 NULL 的注册表,因为如果您不这样做,您可以将 case 语句的这一部分添加到您的 where 子句中: and (date_fact &lt; :date_input_2 AND id= :id) 和一个解释你的查询和你的表的索引会很高兴看到你的问题。
  • 是的情况1和3不需要数据...插入索引info.t2u
  • 好吧对不起:date_input1 是曾经 > :date_input1

标签: sql performance oracle


【解决方案1】:

您只寻找一排。所以,做三个不同的子查询,每个得到一行,然后选择你想要的:

select date_insert, date_fact, data
from (select date_insert, date_fact, data
      from ((select date_insert, date_fact, data, 2 as check
             from (select date_insert, date_fact,
                          (CASE WHEN (date_fact < :date_input_1 AND id= :id) then NULL
                                WHEN (date_fact < :date_input_2 AND id= :id) then data
                                ELSE NULL
                           end) as data
                   from MY_BIG_TABLE
                   where date_fact < :date_input_1 and date_insert > :date_input3
                   order by date_fact desc
                  ) t
             where rownum = 1
            ) union all
            (select date_insert, date_fact, data, 1 as check
             from (select date_insert, date_fact,
                          (CASE WHEN (date_fact < :date_input_1 AND id= :id) then NULL
                                WHEN (date_fact < :date_input_2 AND id= :id) then data
                                ELSE NULL
                           end) as data
                   from MY_BIG_TABLE
                   where date_fact < :date_input_2 and date_insert > :date_input3
                   order by date_fact asc
                  ) t
             where rownum = 1
            ) union all
            (select date_insert, date_fact, data, 0 as check
             from (select date_insert, date_fact,
                          (CASE WHEN (date_fact < :date_input_1 AND id= :id) then NULL
                                WHEN (date_fact < :date_input_2 AND id= :id) then data
                                ELSE NULL
                           end) as data
                   from MY_BIG_TABLE
                   where date_insert > :date_input3
                   order by date_fact desc
                  ) t
             where rownum = 1
            )
           ) t
      order by check desc
     ) t
where rownum = 1;

Oracle 应该足够聪明,可以将索引用于子查询,因此它实际上可能运行得非常快。

【讨论】:

  • 它应该是一个解决方案,但它更有效? (+1)
  • @Kombajnzbożowy 。 . .谢谢你。我是按照文字描述来的。该条件适用于每个子查询。
  • @venergiac 。 . .如果子查询可以使用date_fact 上的索引,效率会更高。这又取决于分区和索引方案。
最近更新 更多