编辑:抱歉,我忘记添加重要条件value1 - value 2 <> 0;
。没有它,结果有~111k记录。并且当我使用CTE重写查询时,在最大日期获取代码集以加入主表,我认为索引似乎无法帮助我的情况。
- ==================================
我们有一个查询(CTE),可以获取最新日期的记录。
对于最糟糕的情况之一,这需要8.6秒才能获得11k行。
表table_name
有3.1密耳行。
目前此查询使用全表扫描。我尝试但无法找到要在此查询中添加的索引。任何人都可以调整它吗?
--sample - one of worse cases
p_filter_code_1 VARCHAR2(200) := ' ';
p_filter_code2 VARCHAR2(10) := ' ';
p_filter_code3 VARCHAR2(10) := ' ';
p_filter_code4 VARCHAR2(10) := ' ';
p_filter_code5 VARCHAR2(10) := ' ';
p_filter_start_date NUMBER := 20170101;
p_filter_end_date NUMBER := 20171231;
--===============
SELECT code_2, code_3, code_4, code5
value1, value2
FROM (
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY code_1, code_2, code_3, code_4, code_5 ORDER BY date_col DESC) AS rn
FROM table_name t
WHERE
(
code_1 IN (SELECT code_1 FROM temp_code)
)
AND date_col < p_filter_start_date
AND (code_2 LIKE p_filter_code2 OR p_filter_code2 = ' ')
AND (code_3 LIKE p_filter_code3 OR p_filter_code3 = ' ')
AND (code_4 = p_filter_code4 OR p_filter_code4 = ' ')
AND (code_5 = p_filter_code5 OR p_filter_code5 = ' ')
)
WHERE rn = 1 AND value1 - value 2 <> 0;
这是code_1_table和temp_code的示例值,带有来自用户的过滤器:'1002,1020-1025,1030,1040-1050'(就像单词中的打印页面)
code_1_table (sample)
code_1 code_1_name
1001 test
1002 x..
1023 .sona
1025 .sojj
1026 .oifhal
temp_code sample records with p_filter_code_1 := '1002,1020-1025,1030,1040-1050'
code_1
1002
1023
1025
CREATE TABLE table_name
(code_1 VARCHAR2(10 BYTE) ,
code_2 VARCHAR2(20 BYTE) ,
code_3 VARCHAR2(20 BYTE) ,
code_4 VARCHAR2(25 BYTE) ,
code_5 VARCHAR2(25 BYTE) ,
value1 NUMBER,
value2 NUMBER,
value3 NUMBER,
value4 NUMBER,
date_col NUMBER )
ALTER TABLE table_name
ADD CONSTRAINT table_name_p
PRIMARY KEY (code_1, code_2, code_3, code_4, code_5, date_col)
/
答案 0 :(得分:0)
执行select t.*...
Oracle最有可能跳过t
上的任何索引。
也许您可以尝试在date_col
(或已排序的索引)上创建索引并使用with
构造来实现数据集,您可以使用row_number
获取最新记录,然后在table_name
上与rowid
加入。
答案 1 :(得分:0)
确保table_name.code_1和temp_code.t_code1上有NOT NULL约束 索引可能对您没有帮助,除非您的table_name包含大量列,并且此查询所需的8列都在其自己的索引结构中。
您的查询需要处理相当多的行,并且可能永远不会是亚秒,但是,您使用分析函数的输出作为过滤器,其中分组/聚合更有效,因此通过重写您的查询如下所示,你会看到略有改善。
select t.code_2
, t.code_3
, t.code_4
, t.code5
, max(t.value1) keep (dense_rank last order by date_col) value1
, max(t.value2) keep (dense_rank last order by date_col) value2
from table_name t
inner join temp_code tc on (t.code_1 = tc.code_1)
where t.date_col < l_filter_start_date
and (t.code_2 LIKE l_filter_code2 OR l_filter_code2 = ' ')
and (t.code_3 LIKE l_filter_code3 OR l_filter_code3 = ' ')
and (t.code_4 = l_filter_code4 OR l_filter_code4 = ' ' )
and (t.code_5 = l_filter_code5 OR l_filter_code5 = ' ' )
group by t.code_1
, t.code_2
, t.code_3
, t.code_4
, t.code5
答案 2 :(得分:-1)
实际上,我相信一旦你编写了window函数,Oracle就不愿意使用索引了。请改用GROUP BY + MAX
。
SELECT tn.code_2, tn.code_3, tn.code_4, tn.code5,
tn.value1, tn.value2
FROM table_name tn
JOIN (
SELECT code_1, code_2, code_3, code_4, code_5, max(date_col) max_date_col
FROM table_name t
WHERE
(
code_1 IN (SELECT code_1 FROM temp_code)
)
AND date_col < l_filter_start_date
AND (code_2 LIKE l_filter_code2 OR l_filter_code2 = ' ')
AND (code_3 LIKE l_filter_code3 OR l_filter_code3 = ' ')
AND (code_4 = l_filter_code4 OR l_filter_code4 = ' ' )
AND (code_5 = l_filter_code5 OR l_filter_code5 = ' ' )
GROUP BY code_1, code_2, code_3, code_4, code_5
) t ON tn.code_1 = t.code_1,
tn.code_2 = t.code_2,
tn.code_3 = t.code_3,
tn.code_4 = t.code_4,
tn.code_5 = t.code_5,
tn.max_date_col = t.date_col
并创建像这样的索引
create index ix_table_name_code_max on table_name (
date_col, code_1, code_2, code_3, code_4, code_5, value1, value2);