Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / IBM DB2, WebSphere, IMS, U2, etc Новый топик    Ответить
 Почему не используется индекс при самом обычном джойне?  [new]
Vetal
Member

Откуда: Киев
Сообщений: 1019
Всем привет!

А задача предельно простая: есть две таблицы. Нужно сделать джойн этих таблиц и вывести первые две результирующие записи.
Размер этих таблиц - по 140000 записей в каждой. Запрос выполняется 15 секунд. Смотрю по плану - сервер ДБ2 при выполнения джойна не использует индексы (а использует MSJOIN вместо NLJOIN). Не могу понять, почему. Разьясните, пожалуйста, как я могу ускорить работу этого джойна?

Версия базы - DB2 8.2 (фикспак тот, который месяц назад был последним, это вроде 13-й)

Помогите пожалуйста!

А теперь подробная информация.

Запрос:
select * from ( 
    select rownumber() over(order by Document.dcm_viewFrom desc) as rownumber_, Document.*, News.*
    from News join Document on News.dcm_unid=Document.dcm_unid) 
as temp_ 
where rownumber_ <= 2

Рисунок плана выполнения запроса находится по ссылке:
план джойна или здесь: плай джойна 2

Скрипт создания таблицы Document

CREATE TABLE LIGAOL.DOCUMENT ( 
    DCM_UNID      	CHARACTER(32) NOT NULL,
    ENTT_ID       	VARCHAR(32),
    DCM_IDENTIFIER	CHARACTER(12) NOT NULL,
    DCM_TITLE     	VARCHAR(254),
    DCM_BODY      	BLOB(5000000),
    DCM_CREATOR   	VARCHAR(62),
    DCM_DATE      	TIMESTAMP,
    DCM_TYPE      	INTEGER,
    DCM_ISVIEWABLE	SMALLINT,
    DCM_VIEWFROM  	TIMESTAMP,
    DCM_VIEWTO    	TIMESTAMP,
    DCM_AUTHORS   	VARCHAR(126),
    PRIMARY KEY(DCM_UNID)
)
GO
ALTER TABLE LIGAOL.DOCUMENT
    ADD CONSTRAINT CC1160057360992
	UNIQUE (DCM_IDENTIFIER)
GO
ALTER TABLE LIGAOL.DOCUMENT
    ADD CONSTRAINT F_DOC2ENTT
	FOREIGN KEY(ENTT_ID) REFERENCES LIGAOL.ENTITY(ENTT_ID)
GO
CREATE INDEX LIGAOL.DCM_FV_ENID
    ON LIGAOL.DOCUMENT(DCM_VIEWFROM DESC, ENTT_ID)  PCTFREE 10 MINPCTUSED 10
GO
CREATE INDEX LIGAOL.DOC2ENTT_FK
    ON LIGAOL.DOCUMENT(ENTT_ID)
GO

Скрипт создания таблицы NEWS:

CREATE TABLE LIGAOL.NEWS ( 
    DCM_UNID         	CHARACTER(32) NOT NULL,
    RBC_ID           	INTEGER,
    NWS_TOP          	SMALLINT,
    NWS_FIO          	VARCHAR(512),
    NWS_ANNOTATION   	VARCHAR(2048),
    NWS_LAWESCORT    	CLOB(65000),
    NWS_CONTACTINFO  	CLOB(16000),
    NWS_SHOWSIGNATURE	SMALLINT,
    NWS_PICTURENAME  	VARCHAR(256),
    NWS_ISARCHIVE    	SMALLINT,
    PRIMARY KEY(DCM_UNID)
)
GO
ALTER TABLE LIGAOL.NEWS
    ADD CONSTRAINT F_RBC_TO_NWS
	FOREIGN KEY(RBC_ID) REFERENCES LIGAOL.RUBRIC(RBC_ID)
GO
ALTER TABLE LIGAOL.NEWS
    ADD CONSTRAINT FK24FEF311B2BCF5
	FOREIGN KEY(DCM_UNID) REFERENCES LIGAOL.DOCUMENT(DCM_UNID)
GO
CREATE INDEX LIGAOL.RBC_TO_NWS_FK
    ON LIGAOL.NEWS(RBC_ID)
GO

Почему DB2 не использует индекс при джойне?

Всем заранее спасибо!
6 окт 06, 00:50    [3228150]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Vetal
Member

Откуда: Киев
Сообщений: 1019
Да, статистика вся построена и актуальна. Вот она:
Статистика индекса по Document.dcm_unid и Статистика индекса по News.dcm_unid
6 окт 06, 00:57    [3228159]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Mark Barinstein
Member

Откуда: Москва
Сообщений: 4946
Здравствуйте.

Создайте индекс по полю news.dcm_unid, соберите статистику.
И попробуйте
select * 
from News 
join Document on News.dcm_unid=Document.dcm_unid
order by Document.dcm_viewFrom desc
fetch first 2 rows only;
6 окт 06, 09:29    [3228675]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Vetal
Member

Откуда: Киев
Сообщений: 1019
Mark Barinstein
Здравствуйте.

Создайте индекс по полю news.dcm_unid, соберите статистику.
И попробуйте
select * 
from News 
join Document on News.dcm_unid=Document.dcm_unid
order by Document.dcm_viewFrom desc
fetch first 2 rows only;

По полю dcm_unid присутствует первичный ключ. Статистика собрано. Выполняю Ваш запрос. Получаю 6 секунд на выполение этого запроса, и следующий план:
План выполнения джойна
Как видите, план фактически тот же самый.
Подскажите, что я могу сделать, чтобы этот запрос работал быстрее?
9 окт 06, 11:36    [3236007]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
gardenman
Member

Откуда: С-Петербург
Сообщений: 2347
Ничто так не улучшает производительность как перепроектирование.
9 окт 06, 11:57    [3236160]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
gardenman
Member

Откуда: С-Петербург
Сообщений: 2347
Используйте конструкцию With и Fetch first засуньте куда-нить внутрь.
Чтоб сначала отфильтровалось некоторое число записей, а потому ток джойнилось, а то у вас сначала все выбирается, всё джойнится, а потом ток 2 записи берется.
9 окт 06, 12:03    [3236220]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
gardenman
Member

Откуда: С-Петербург
Сообщений: 2347
Что касается ф-ции rownumber(), то лучше их вообще не юзать для приложений , которые должны возвращать данные быстро.
Если есть страстное желание пронумеровать записи в запросе, то напишите свою собственную функцию на C. Здесь были примеры подобного рода.
Опять же, чтобы ограничивать выборку лучше на самом начальном этапе, и при помощи fetch first. А чтобы добиться правильносй сортировки юзайте ORDER BY ORDER OF.
9 окт 06, 12:09    [3236289]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Mark Barinstein
Member

Откуда: Москва
Сообщений: 4946
Какой план запроса у вас при (статистика на индекс LIGAOL.DCM_FV_ENID должна быть заранее собрана):
with t as 
(
select 
from LIGAOL.DOCUMENT
order by dcm_viewFrom desc
fetch first 2 rows only
)
select * from t;
9 окт 06, 12:12    [3236313]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Mark Barinstein
Member

Откуда: Москва
Сообщений: 4946
Упс!
разумеется
select DCM_UNID from ...
9 окт 06, 12:14    [3236324]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Vetal
Member

Откуда: Киев
Сообщений: 1019
Выполнился Ваш запрос очень быстро. План вот:
план запроса
9 окт 06, 12:32    [3236458]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Alexander Mozhaev
Member

Откуда:
Сообщений: 116
Vetal
Выполнился Ваш запрос очень быстро. План вот:
план запроса


У тебя сколько записей в таблице, они все помещаются в памяти? - да, зачем тогда индекс использовать.
Оптимизатор у нас "умный":)
9 окт 06, 13:17    [3236785]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Vetal
Member

Откуда: Киев
Сообщений: 1019
Alexander Mozhaev
Vetal
Выполнился Ваш запрос очень быстро. План вот:
план запроса


У тебя сколько записей в таблице, они все помещаются в памяти? - да, зачем тогда индекс использовать.
Оптимизатор у нас "умный":)

В таблицах по 200 000 записей. Причем в каждой из них есть блоб килобайт так на 10-20...
9 окт 06, 13:23    [3236821]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Alexander Mozhaev
Member

Откуда:
Сообщений: 116
Попробуй убрать из запроса "where rownumber_ <= 2" и посмотреть план запроса
9 окт 06, 13:29    [3236869]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Vetal
Member

Откуда: Киев
Сообщений: 1019
Alexander Mozhaev
Попробуй убрать из запроса "where rownumber_ <= 2" и посмотреть план запроса

Выполнил следующий запрос:
select * from ( 
    select rownumber() over(order by Document.dcm_viewFrom desc) as rownumber_, Document.*, News.*
    from News join Document on News.dcm_unid=Document.dcm_unid) 
as temp_ 
План получился такой:
план запроса
9 окт 06, 13:35    [3236903]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Mark Barinstein
Member

Откуда: Москва
Сообщений: 4946
А такого:
with t as 
(
select DCM_UNID
from LIGAOL.DOCUMENT
where dcm_viewFrom<current timestamp
order by dcm_viewFrom desc
fetch first 2 rows only
)
select * from t;
9 окт 06, 13:40    [3236934]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
Alexander Mozhaev
Member

Откуда:
Сообщений: 116
Ты rownumber_ еще где-то используешь кроме как для отсечения строк?

Это тоже самое только без rownumber_
select
Document.*, News.*
from Document
inner join
News
on Document.dcm_unid=News.dcm_unid
order by Document.dcm_viewFrom desc

Добавь потом:
fetch first 2 rows only
9 окт 06, 13:49    [3236984]     Ответить | Цитировать Сообщить модератору
 Re: Почему не используется индекс при самом обычном джойне?  [new]
gals
Member

Откуда: Санкт-Петербург
Сообщений: 195
По моему, план запроса оптимален.
Вы хотите вывести все поля из двух таблиц. Серверу дешевле произвести полное сканирование таблицы с последующей сортировкой, нежели обход по индексу и чтение таблицы.
Ваш первый план запроса показывает, что самым затратным является не MSJOIN(7), а SORT(11)+SORT(19). Причем, SORT(19) в большей степени.

Попробуйте в первой выборке отобрать только поле связывания:
SELECT Document.dcm_unid 
FROM News JOIN Document ON News.dcm_unid=Document.dcm_unid
FETCH FIRST 2 ROWS ONLY
Этот запрос явно будет использовать только индексы без обращения к таблицам.
После этого можно сделать выборку всех данных из двух таблиц.
10 окт 06, 10:17    [3240017]     Ответить | Цитировать Сообщить модератору
Все форумы / IBM DB2, WebSphere, IMS, U2, etc Ответить