Oracle 11g: индекс не используется в запросе «выбрать отдельный» - PullRequest
7 голосов
/ 24 сентября 2011

Мой вопрос касается Oracle 11g и использования индексов в запросах SQL.

В моей базе данных есть таблица, которая имеет следующую структуру:

Table tab (
  rowid NUMBER(11),
  unique_id_string VARCHAR2(2000),
  year NUMBER(4),
  dynamic_col_1 NUMBER(11),
  dynamic_col_1_text NVARCHAR2(2000)
 ) TABLESPACE tabspace_data;

Я создал дваиндексы:

CREATE INDEX Index_dyn_col1 ON tab (dynamic_col_1, dynamic_col_1_text) TABLESPACE tabspace_index;
CREATE INDEX Index_unique_id_year ON tab (unique_id_string, year) TABLESPACE tabspace_index;

Таблица содержит от 1 до 2 миллионов записей.Я извлекаю из него данные, выполняя следующую команду SQL:

SELECT distinct
 "sub_select"."dynamic_col_1" "AS_dynamic_col_1","sub_select"."dynamic_col_1_text" "AS_dynamic_col_1_text"
FROM 
(
    SELECT "tab".*  FROM "tab"
    where "tab".year = 2011
) "sub_select"

К сожалению, для выполнения запроса требуется около 1 часа, хотя я создал оба индекса, описанных выше.План объяснения показывает, что Oracle использует «Таблицу полного доступа», то есть полное сканирование таблицы.Почему индекс не используется?

В качестве эксперимента я протестировал следующую команду SQL:

SELECT DISTINCT
 "dynamic_col_1" "AS_dynamic_col_1", "dynamic_col_1_text" "AS_dynamic_col_1_text"
 FROM "tab"

Даже в этом случае индекс не используется и выполняется полное сканирование таблицы..

В моей реальной базе данных таблица содержит больше индексированных столбцов, таких как «dynamic_col_1» и «dynamic_col_1_text».Весь индексный файл имеет размер около 50 ГБ.

Несколько дополнительных сведений:

  • База данных - Oracle 11g, установленная на моем локальном компьютере.
  • Iиспользуйте Windows 7 Enterprise 64bit.
  • Весь индекс разделен на 3 dbf-файла размером около 50 ГБ.используйте индекс в первом запросе.Поскольку первый запрос используется другой программой для извлечения данных из базы данных, его вряд ли можно изменить.Поэтому было бы неплохо настроить таблицу вместо этого.

    Заранее спасибо.

    [01.10.2011: ОБНОВЛЕНИЕ]

    Я думаю, что нашел решение дляпроблема.Оба столбца dynamic_col_1 и dynamic_col_1_text могут иметь значение NULL.После изменения таблицы, запрещающей значения NULL в обоих столбцах, и добавления нового индекса исключительно для столбца year, Oracle выполняет быстрое сканирование индекса.Преимущество состоит в том, что теперь выполнение запроса занимает около 5 секунд, а не 1 час, как раньше.

Ответы [ 6 ]

5 голосов
/ 24 сентября 2011

Вы уверены, что доступ к индексу будет быстрее, чем полное сканирование таблицы?В качестве очень приблизительной оценки, полное сканирование таблицы происходит в 20 раз быстрее, чем чтение индекса.Если в 2011 году tab содержит более 5% данных, неудивительно, что Oracle будет использовать полное сканирование таблицы.И, как упоминали @Dan и @Ollie, с year в качестве второго столбца, это сделает индекс еще медленнее.

Если индекс действительно быстрее, чем проблема, вероятно, плохая статистика.Есть сотни способов, которыми статистика может быть плохой.Очень кратко, вот что я посмотрю вначале:

  1. Запустите план объяснения с указанием и без указателя индекса.Количество кардиналов уменьшилось в 10 или более раз?Времена отключены в 10 раз или больше?
  2. Если количество элементов отключено, убедитесь, что в таблице и индексе есть актуальная статистика, и вы используете разумный ESTIMATE_PERCENT (DBMS_STATS.AUTO_SAMPLE_SIZE почти всегдалучше всего для 11g).
  3. Если время вышло, проверьте статистику рабочей нагрузки.
  4. Используете ли вы параллелизм?Oracle всегда предполагает почти линейное улучшение параллелизма, но на настольном компьютере с одним жестким диском вы, вероятно, вообще не увидите никаких улучшений.

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

4 голосов
/ 24 сентября 2011

Ваш индекс должен быть:

CREATE INDEX Index_year 
ON tab (year) 
TABLESPACE tabspace_index;

Кроме того, ваш запрос может быть просто:

SELECT DISTINCT
       dynamic_col_1 "AS_dynamic_col_1",
       dynamic_col_1_text "AS_dynamic_col_1_text"
  FROM tab
 WHERE year = 2011;

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

Надеюсь, это поможет ...

2 голосов
/ 24 сентября 2011

У меня нет экземпляра Oracle под рукой, так что это несколько догадки, но я склонен сказать, что у вас составной индекс в неправильном порядке. Если вы указали year в качестве первого столбца в индексе, он может использовать его.

1 голос
/ 25 сентября 2011

Ваш второй тестовый запрос:

SELECT DISTINCT
"dynamic_col_1" "AS_dynamic_col_1", "dynamic_col_1_text" "AS_dynamic_col_1_text"
FROM "tab"

не будет использовать индекс, потому что у вас нет предложения WHERE, поэтому вы просите Oracle прочитать каждую строку в таблице. В этой ситуации полное сканирование таблицы является более быстрым методом доступа.

Кроме того, как отмечали другие авторы, ваш индекс по ГОДУ имеет его во втором столбце. Oracle может использовать этот индекс, выполнив сканирование с пропуском, но это приведет к снижению производительности, и в зависимости от размера вашей таблицы Oracle может просто решить снова использовать FTS.

1 голос
/ 25 сентября 2011

Не знаю, насколько это актуально, но я проверил следующий запрос:

SELECT DISTINCT
"dynamic_col_1" "AS_dynamic_col_1", "dynamic_col_1_text" "AS_dynamic_col_1_text"
FROM "tab"
WHERE "dynamic_col_1" = 123 AND "dynamic_col_1_text" = 'abc'

План объяснения для этого запроса показывает, что Oracle использует сканирование индекса в этом сценарии.

Столбцы dynamic_col_1 и dynamic_col_1_text обнуляются. Влияет ли это на использование индекса?

01.10.2011: ОБНОВЛЕНИЕ]

Я думаю, что нашел решение проблемы. Оба столбца dynamic_col_1 и dynamic_col_1_text имеют значение NULL. После изменения таблицы, запрещающей значения NULL в обоих столбцах, и добавления нового индекса исключительно для года столбца, Oracle выполняет быстрое сканирование индекса. Преимущество состоит в том, что теперь выполнение запроса занимает около 5 секунд, а не 1 час, как раньше.

0 голосов
/ 25 сентября 2011

Попробуйте это:

1) Создать индекс по полю года (см. Ответ Олли).

2) И затем используйте этот запрос:

SELECT DISTINCT
dynamic_col_1
,dynamic_col_1_text
FROM tab 
WHERE ID (SELECT ID FROM tab WHERE year=2011)

или

SELECT DISTINCT
dynamic_col_1
,dynamic_col_1_text
FROM tab 
WHERE ID (SELECT ID FROM tab WHERE year=2011)
GROUP BY dynamic_col_1, dynamic_col_1_text

Может быть, это поможет вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...