我们在oracle中使用范围分区在年份值上划分了大量数据。我们使用了范围分区,但每个分区只包含一年的数据。当我们编写针对特定年份的查询时,oracle会从该分区获取信息,但仍会检查年份是否是我们指定的年份。由于今年的列不是索引的一部分,因此它从表中获取年份并对其进行比较。我们已经看到,只要查询获取表数据,它就会变得太慢。
我们能否以某种方式避免oracle比较年份值,因为我们肯定知道该分区只包含一年的信息。
更新
执行分区的年份数据类型的类型为编号。
我们没有选择任何其他列。我只是在执行count(*)
而没有选择任何列。
如果我们删除条件并将查询定位到特定分区为
select count(*) from table_name partition(part_2004)
速度更快
而
select count(*) from table
where year = 2004
速度较慢。
分区是年份列,这是一个数字,如下所示
年份低于2005年part_2004
年份低于2006年part_2005
年不到2007年part_2006
......等等
答案 0 :(得分:5)
如果没有解释计划或表格定义,很难说出发生了什么。我的第一个猜测是你有没有year
列的LOCAL分区索引。它们帮助分区上的COUNT(*),但是当您查询一年时(至少在10.2.0.3上),它们似乎不会被使用。
这是一个重现您的发现(和解决方法)的小例子:
SQL> CREATE TABLE DATA (
2 YEAR NUMBER NOT NULL,
3 ID NUMBER NOT NULL,
4 extra CHAR(1000)
5 ) PARTITION BY RANGE (YEAR) (
6 PARTITION part1 VALUES LESS THAN (2010),
7 PARTITION part2 VALUES LESS THAN (2011)
8 );
Table created
SQL> CREATE INDEX ix_id ON DATA (ID) LOCAL;
Index created
SQL> INSERT INTO DATA
2 (SELECT 2009+MOD(ROWNUM, 2), ROWNUM, 'A' FROM DUAL CONNECT BY LEVEL <=1e4);
10000 rows inserted
SQL> EXEC dbms_stats.gather_table_stats(USER, 'DATA', CASCADE=>TRUE);
PL/SQL procedure successfully completed
现在比较两个解释计划:
SQL> SELECT COUNT(*) FROM DATA WHERE YEAR=2010;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=197 Card=1 Bytes=4)
1 0 SORT (AGGREGATE)
2 1 PARTITION RANGE (SINGLE) (Cost=197 Card=5000 Bytes=20000)
3 2 TABLE ACCESS (FULL) OF 'DATA' (TABLE) (Cost=197 Card=5000...)
SQL> SELECT COUNT(*) FROM DATA PARTITION (part1);
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=11 Card=1)
1 0 SORT (AGGREGATE)
2 1 PARTITION RANGE (SINGLE) (Cost=11 Card=5000)
3 2 INDEX (FULL SCAN) OF 'IX_ID' (INDEX) (Cost=11 Card=5000)
正如您所看到的,直接查询年份时使用的索引不。将年份添加到LOCAL索引时,将使用它。我使用COMPRESS 1指令告诉Oracle压缩第一列。生成的索引与原始索引的大小几乎相同(由于压缩),因此不应影响性能。
SQL> DROP INDEX ix_id;
Index dropped
SQL> CREATE INDEX ix_id ON DATA (year, ID) LOCAL COMPRESS 1;
Index created
SQL> SELECT COUNT(*) FROM DATA WHERE YEAR=2010;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=12 Card=1 Bytes=4)
1 0 SORT (AGGREGATE)
2 1 PARTITION RANGE (SINGLE) (Cost=12 Card=5000 Bytes=20000)
3 2 INDEX (RANGE SCAN) OF 'IX_ID' (INDEX) (Cost=12 Card=5000...)
答案 1 :(得分:2)
你确定它只是为了查看年份吗?也许还有其他专栏?
该查询是否仅适用于(分区)索引?
如果它还需要转到表中,那额外的检查费用不高(如果分区是正确的)。
您可以发布查询和执行计划吗?