Проверка пропуска диапазона диапазона - PullRequest
2 голосов
/ 29 марта 2010

У нас есть большой объем данных, разбитых по значению года, используя диапазонную секцию в Oracle.Мы использовали раздел диапазона, но каждый раздел содержит данные только за один год.Когда мы пишем запрос, ориентированный на определенный год, oracle извлекает информацию из этого раздела, но все равно проверяет, является ли год указанным нами.Так как этот столбец года не является частью индекса, он выбирает год из таблицы и сравнивает его.Мы видели, что каждый раз, когда запрос идет на выборку данных таблицы, он становится слишком медленным.

Можем ли мы как-то избежать оракула, сравнивая значения года, поскольку мы точно знаем, что раздел содержит информацию только за один год.

Обновление:

  1. Тип данных года, для которого выполняется раздел, имеет номер типа.

  2. Мы не выбираемлюбые дополнительные столбцы.Я просто выполняю count(*), а столбцы не выбираются.

  3. Если мы удалим условие и нацелим запрос на конкретный раздел как select count(*) from table_name partition(part_2004), он будет быстрее, а select count(*) from table where year = 2004это намного медленнее.

  4. Разделение по столбцу год, который является числом и выполняется примерно так:

    год меньше, чем 2005меньше чем 2006 часть_2005

    год меньше чем 2007 часть_2006

... и так далее

Ответы [ 2 ]

5 голосов
/ 29 марта 2010

Без плана объяснения или определения таблицы действительно трудно сказать, что происходит. Мое первое предположение состоит в том, что у вас есть МЕСТНЫЕ секционированные индексы без столбца year. Они помогают с 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...)
2 голосов
/ 29 марта 2010

Вы уверены, что он идет к таблице только для проверки года? Может быть, есть другие вовлеченные столбцы?

Должен ли запрос работать только с (разделенными) индексами?

Если ему все равно нужно пойти к столу, дополнительная проверка не стоит больших затрат (если раздел правильный).

Можете ли вы опубликовать запрос и план выполнения?

...