Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / IBM DB2, WebSphere, IMS, U2 [игнор отключен] [закрыт для гостей] / fetch first and join / 12 сообщений из 12, страница 1 из 1
25.11.2015, 13:30
    #39113082
olzhas
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
Есть запрос
Код: sql
1.
2.
3.
4.
5.
6.
SELECT        
        t0.BR_ID,
        t0.BR_STATUS_ID        
FROM NABRK.BR t0         
ORDER BY t0.BR_ID DESC
FETCH FIRST 25 ROWS ONLY


Он обрабатывается за 0.05 секунд, по плану запроса все хорошо используется индекс и происходит fetch только нужных записей.

теперь добавляем справочник в запрос (Foreing key имеется, поле t0.BR_STATUS_ID не допускает пустых значений)

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
SELECT        
        t0.BR_ID,
        t0.BR_STATUS_ID,        
        t1.BR_STATUS_NAME
FROM NABRK.BR t0 
        INNER JOIN NABRK.BR_STATUS t1 ON t0.BR_STATUS_ID = t1.BR_STATUS_ID
      ORDER BY t0.BR_ID DESC
      FETCH FIRST 25 ROWS ONLY


и запрос уже работает 1.5 секунды.
Теперь по плану запроса он все выбирает сортирует а потом джойнит справочник.
т.е. получается FETCH FIRST он использует в самом конце. Можно конечно исправить ситуацию с помощью подзапросов, но это не очень красиво выглядит.

можно ли эту ситуацию исправить без подзапросов?
...
Рейтинг: 0 / 0
25.11.2015, 13:51
    #39113106
Mark Barinstein
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
olzhas,

По этим картинкам ничего не понятно.
Где описание индексов, где именно второй картинке outer и inner таблицы? Предположительно BR - outer, но на всякий...
Индексы, похоже, используются разные для доступа к BR в разных запросах.

Опять же, если не нравится этот план, считаете, что во 2-м случае должен использоваться другой индекс для достуа к BR - составьте оптимизационный профиль, сревните цены запросов.
Можете добавить OPTIMIZE FOR 25 ROWS, проверить - не изменился ли план.
...
Рейтинг: 0 / 0
25.11.2015, 14:06
    #39113129
olzhas
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
Mark Barinstein,

Тут вопрос даже не в использовании индекса (таблица BR_STATUS маленька, у нее всего 8 записей), а то что fetch происходит в самом конце.

я могу переписать запрос так
Код: sql
1.
2.
3.
4.
5.
6.
7.
SELECT        
        t0.BR_ID,
        t0.BR_STATUS_ID,        
        t1.BR_STATUS_NAME
FROM (select * from NABRK.BR t0 ORDER BY t0.BR_ID DESC
      FETCH FIRST 25 ROWS ONLY) t0
        INNER JOIN NABRK.BR_STATUS t1 ON t0.BR_STATUS_ID = t1.BR_STATUS_ID



или вот так
Код: sql
1.
2.
3.
4.
5.
6.
7.
SELECT        
        t0.BR_ID,
        t0.BR_STATUS_ID,        
        (select t1.BR_STATUS_NAME from nabrk.br_status t1 where t0.BR_STATUS_ID = t1.BR_STATUS_ID)
FROM NABRK.BR t0         
      ORDER BY t0.BR_ID DESC
      FETCH FIRST 25 ROWS ONLY;



результат не изменится, а запрос будет выполнятся как и первый за 0.05 секунд.
...
Рейтинг: 0 / 0
25.11.2015, 14:29
    #39113155
Mark Barinstein
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
olzhasТут вопрос даже не в использовании индекса (таблица BR_STATUS маленька, у нее всего 8 записей), а то что fetch происходит в самом конце.Как это не в использовании индекса?
Я писал про индексы на BR, а не на BR_STATUS.
У вас что, в обоих случаях используется один и тот же индекс на BR?

По поводу маленькой BR_STATUS. А DB2 знает об этом? Вы статистику собирали на нее и на BR?
...
Рейтинг: 0 / 0
26.11.2015, 09:18
    #39113737
olzhas
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
Mark Barinstein,

Я как то и не обратил внимание что используется другой индекс. Я не понимаю почему база решила именно его взять, возможно из-за того что у него самый высокий показатель sequntal_page (это к вопросу из предыдущего моего топика).

Я сделал реогранизацию таблицы а потом и индексов. план запроса поменялся, и запросы стали выполнятся уже 0.3 секунды. Теперь он использует full table scan. Что по планам запроса выглядит как выгоднее, но по времени он выполняется дольше.
...
Рейтинг: 0 / 0
26.11.2015, 09:33
    #39113752
olzhas
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
Я так понимаю.
В пером случае обрезание происходит на этапе fetch по мене загрузки данных.
Во втором случае обрезание происходит на этапе sort, но для того что бы сделать sort надо загрузить все данные с таблицы.
и вот тут самое интересное оптимизатор не использует IXSCAN + FETCH потому что это дороже чем просто TBSCAN (34 тыс против 15 тыс) получается что он не смотрит на количество указанное в fetch frist N rows olny. Если это так тогда почему в первом случае он тоже не использует TBSCAN, это ведь дешевле.
...
Рейтинг: 0 / 0
26.11.2015, 09:37
    #39113755
olzhas
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
если переписать запрос вот так
Код: sql
1.
2.
3.
4.
5.
6.
7.
SELECT        
        t0.BR_ID,
        t0.BR_STATUS_ID,        
        t1.BR_STATUS_NAME
FROM (select * from  NABRK.BR t0 ORDER BY t0.BR_ID DESC
      FETCH FIRST 25 ROWS ONLY) t0
        INNER JOIN NABRK.BR_STATUS t1 ON t0.BR_STATUS_ID = t1.BR_STATUS_ID



то получим такой план запрос. какой он и должен быть.
...
Рейтинг: 0 / 0
26.11.2015, 10:15
    #39113778
Victor Metelitsa
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
Чтобы понимать "почему", желательно понимать принципы расчёта стоимости, я знаю лишь одну-единственную книжку, но и та про Oracle. Вкратце и очень сильно упрощённо, основная часть стоимости обычно(!) идёт с предсказанного количества чтения, но не голое количество блоков, а с учётом предсказанной одноблочности и мультиблочности, и считается с использованием OVERHEAD И TRANSFERRATE табличного пространства. И расчёты эти, по большому счёты, вилами на воде писаны, ибо основаны на статистике (а средний случай совсем не обязан подходить к вашему частному), часто основаны на догадках и часто не могут учитывать реальную обстановку.

А быстрее всего ваш запрос, наверное, будет работать при UNIQUE INDEX ... ON NABRK.BR(BR_id) INCLUDE(BR_STATUS_ID).
...
Рейтинг: 0 / 0
26.11.2015, 10:30
    #39113795
Mark Barinstein
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
olzhas,

FETCH FRIST N ROWS не оказывает на оптимизатор влияния. Это только указание прекратить возврат записей после N записей.
Если вы хотите повлиять на оптимизатор, используйте в дополнение к этому OPTIMIZE FOR N ROWS.
Например, OPTIMIZE FOR 1 ROW
...
Рейтинг: 0 / 0
26.11.2015, 11:10
    #39113829
olzhas
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
Mark Barinstein,

Вот спасибо! Теперь все работает так как надо.

итоговый запрос

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT        
        t0.BR_ID,
        t0.BR_STATUS_ID,        
        t1.BR_STATUS_NAME
FROM NABRK.BR t0 
        INNER JOIN NABRK.BR_STATUS t1 ON t0.BR_STATUS_ID = t1.BR_STATUS_ID
      ORDER BY t0.BR_ID DESC
      FETCH FIRST 25 ROWS ONLY
      OPTIMIZE FOR 1 ROWS
...
Рейтинг: 0 / 0
26.11.2015, 14:00
    #39114018
Victor Metelitsa
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
Мысли по этому поводу:

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

Марк предложил сказать оптимизатору через OPTIMIZE FOR 1 ROWS, что вы далеко не пойдёте, так что всю таблицу читать будет не надо - и когда есть подходящий индекс, тут он точно выгоден. Нужно просто пройти индекс сверху вниз (пара-тройка-четвёрка чтений страниц индекса) и одно чтение табличной страницы. Это по цене много меньше того, чтобы прочитать все страницы индекса и все страницы таблицы (в варианте без OPTIMIZE FOR), вместо чего было и выбрано простое сканирование таблицы с сортировкой.

До этого, я предложил не обращаться к таблице (путём UNIQUE INDEX ... ON NABRK.BR(BR_id) INCLUDE(BR_STATUS_ID).). Менее, скажем так, правильный вариант (если не прибавить OPTIMIZE FOR к нему). Не исключено, что планом было бы полное чтение индекса, а затем его сортировка(!). Либо читать индекс по порядку одноблочными чтениями - невыгодно, если он не совсем маленький, либо быстренько считать многоблочными - выгодно, если он размером меньше таблицы, но при этом порядок не гарантирован (в Oracle так, и нет причин, чтобы в DB2 было не так).

OPTIMIZE FOR 25 ROWS. возможно, более точное.
OPTIMIZE FOR 1 ROWS - это чтобы принудить к использованию индекса на NABRK.BR наверняка. Но вот что будет с cardinality дальше? План INNER JOIN NABRK.BR_STATUS t1 ON t0.BR_STATUS_ID = t1.BR_STATUS_ID может зависеть от неё. То есть, 1 раз мы ищем в таблице NABRK.BR_STATUS или 25 раз - разница может быть (или не быть).
...
Рейтинг: 0 / 0
26.11.2015, 14:16
    #39114034
olzhas
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
fetch first and join
Victor Metelitsa,

Мой пример часть большого запроса. при одном join OPTIMIZE FOR 25 ROWS работает, но при больших количествах (у меня их 8) оптимизатор уже предпочитает полное сканирование таблицы, поэтому я и поставил OPTIMIZE FOR 1 ROWS, что бы уже наверняка.

строить еще один индекс с include, нет смысла при нескольких join.

В целом проблема была в том что оптимизатор не понимал что требуется небольшое количество записей. конструкция OPTIMIZE FOR 1 ROW решает эту проблему.
...
Рейтинг: 0 / 0
Форумы / IBM DB2, WebSphere, IMS, U2 [игнор отключен] [закрыт для гостей] / fetch first and join / 12 сообщений из 12, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]