Oracle: полное сканирование вместо составного индекса с использованием - PullRequest
2 голосов
/ 24 января 2011

У меня странное поведение оптимизатора оракула:

SELECT a.id,
       a.date_insert,
       a.message#cnt
  FROM T_MESSAGE_TRANSMIT A,
       T_LIST l 
 WHERE a.priority_id = 0 
   AND a.status = 'Q'
   and l.id = a.list_id

Этот запрос производит полное сканирование более T_MESSAGE_TRANSMIT, независимо от того, что это индекс, охватывающий поля priority_id и status:

CREATE BITMAP INDEX INFORMER.IX$MESSAGE_TRANSMIT$6 ON INFORMER.T_MESSAGE_TRANSMIT (STATUS, PRIORITY_ID)

Размер таблицы составляет около 28 миллионов строк, и она была проанализирована 7 дней назад (с того дня было добавлено всего несколько тысяч строк).

Если я воспользуюсь подсказкой /*+index(a IX$MESSAGE_TRANSMIT$6) */, тогда все станет хорошо, а также если я удалю объединение и перепишу запрос на:

SELECT a.id,
       a.date_insert,
       a.message#cnt
  FROM T_MESSAGE_TRANSMIT A,
 WHERE a.priority_id = 0 
   AND a.status = 'Q'

Где я мог ошибиться?

UPD

Проблема была в этой настройке оптимизатора:

optimizer_mode  first_rows_10

1 Ответ

3 голосов
/ 24 января 2011

Какая пропорция строк соответствует идентификатору приоритета / критериям статуса?

Если, например, совпадают 20% строк, то в 20% случаев потребуется посетить строку, чтобы получить дополнительнуюподробности.Если он посещает 20% строк, он, вероятно, посетит 80-90% блоков.В этом случае было бы правильно игнорировать индекс.

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

В этом случае он может получить все совпадающие строки из T_MESSAGE_TRANSMIT, отсортировать их по ID и затем получитьсоответствующие строки из T_LIST.Может также подойти хеш-соединение с T_LIST.

Кроме того, вы уверены, что не хотите просто сделать

SELECT a.id,
       a.date_insert,
       a.message#cnt
  FROM T_MESSAGE_TRANSMIT A
 WHERE a.priority_id = 0 
   AND a.status = 'Q'
   AND a.list_id in (select l.id from T_LIST l)

Если идентификатор не уникален в T_LIST, вашоригинальный SQL будет генерировать дубликаты.

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