SQLinfo.ru - Все о MySQL Webew.ru: теория и практика веб-технологий

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 11.12.2008 17:05:34

COOLim
Участник
Зарегистрирован: 11.12.2008
Сообщений: 7

ПОМОГИТЕ оптимизироваить select!

Здравствуйте уважаемые ГУРУ.
Возникла пробема, не знаю к чему ее отнести. Есть 2 таблицы связанные между собой по таблице связи. Данных в 2-х таблицах приблизительно по 300 000 записей. Произвожу выборку по запросу:

select OBJ_1.ID, OBJ_1.FLD_1, OBJ_2.ID, OBJ_2.FLD_2
from OBJ_1, OBJ_2, LINK
where ((OBJ_1.ID=LINK.ID_1 and OBJ_2.ID=LINK.ID_2)or(OBJ_1.ID=LINK.ID_2 and OBJ_2.ID=LINK.ID_1))

Этот запрос выполняется очень долго (ОЧЕНЬ ДОЛГО, порядка 30 минут!!!!!).
(Замечания к where: необходимо делать двойную проверку т.к. ниезвестно как могли быть связаны объекты через таблицу связи).
Индексы: в каждой таблице по ID,  в таблице связей (LINK) пробовол все возможные типы индексов - не помогло. Сейчас индексов нет.

2 таблицы простые, думаю описывать их нет смылса (ID - primary key, FLDs - столбцы). Таблица связи имеет вид:
LNKID int(20) - ID таблицы
OBJ1_ID int(20) - ID таблицы 1
ID_1 int(20) - ID записи в таблицы 1
OBJ2_ID int(20) - ID таблицы 2
ID_2 - ID записи в таблицы 2
....

Explain запроса возвращает
id    select_type    table      type    possible_keys    key       key_len    ref       rows      Extra                                         
1     SIMPLE         OBJ_1      ALL     IND_1            (null)    (null)     (null)    260124                                                  
1     SIMPLE         LINK    ALL     (null)           (null)    (null)     (null)    331422    Using where                                   
1     SIMPLE         OBJ_2      ALL     IND_2           (null)    (null)     (null)    333487    Range checked for each record (index map: 0x1)

Пробовал перестраиваить запрос, результатов не добился. Если из "where" заменить ((OBJ_1.ID=LINK.ID_1 and OBJ_2.ID=LINK.ID_2)or(OBJ_1.ID=LINK.ID_2 and OBJ_2.ID=LINK.ID_1)) на (OBJ_1.ID=LINK.ID_1 and OBJ_2.ID=LINK.ID_2) то все работает идеально.

ПОМОГИТЕ!!!

Неактивен

 

#2 11.12.2008 17:16:45

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: ПОМОГИТЕ оптимизироваить select!

Попробуйте избавится от OR. Сделать два запроса и UNION

Неактивен

 

#3 11.12.2008 17:28:45

COOLim
Участник
Зарегистрирован: 11.12.2008
Сообщений: 7

Re: ПОМОГИТЕ оптимизироваить select!

Спасибо за быстрый ответ.

explain
select OBJ_1.ID,OBJ_1.FLD_1,OBJ_2.ID,OBJ_2.FLD_2
from OBJ_1, OBJ_2, LINK
where (OBJ_1.ID=link.ID_1 and OBJ_2.id=Link.ID_2)
union
select OBJ_1.ID,OBJ_1.FLD_1,OBJ_2.ID,OBJ_2.FLD_2
from OBJ_1, OBJ_2, LINK
where (OBJ_1.ID=link.ID_2 and OBJ_2.id=Link.ID_1)

id      select_type     table         type    possible_keys    key       key_len    ref                      rows      Extra
1       PRIMARY         LINK                   ALL     (null)           (null)    (null)     (null)                   331422        
1       PRIMARY         OBJ_1         ref     IND_1            IND_1     4          LINK.ID_1    1             
1       PRIMARY         OBJ_2         ref     IND_2           IND_2    4          LINK.ID_2    1             
2       UNION           SD_LINK       ALL     (null)           (null)    (null)     (null)                   331422        
2       UNION           OBJ_1         ref     IND_1            IND_1     4          LINK.ID_2    1             
2       UNION           OBJ_2         ref     IND_2           IND_2    4          LINK.ID_1    1             
Null    UNION RESULT    <union1,2>    ALL     (null)           (null)    (null)     (null)                   Null          

Отрабатывает чуть быстрее, но не летает (было такая идея)!
Бывают запросы сложее (пересечение 3 объектов и более). И вот там как раз эта двойная проверка все и губит, а без нее никуда!

Буду рад любой идеи или направления где капнуть!

ЗЫ. Из-за таких запрос даже научился чуть оптимизировать сервер! smile

Неактивен

 

#4 11.12.2008 17:38:30

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: ПОМОГИТЕ оптимизироваить select!

Для данного конкретного запроса выход напрашивается простой - симметризовать таблицу link. То есть сделать, чтобы наряду с записью
id1, id2 в ней всегда была
id2, id1

Неактивен

 

#5 11.12.2008 18:02:34

COOLim
Участник
Зарегистрирован: 11.12.2008
Сообщений: 7

Re: ПОМОГИТЕ оптимизироваить select!

Спасибо.
Сам думал над этим решением. Но, к сожалению, структруру таблицы на данном этапе меня нельзя. Придется очень много переделовать в программе!
Буду биться дальше. Если чего-нибудь придумаю - напишу!

Неактивен

 

#6 11.12.2008 18:05:45

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: ПОМОГИТЕ оптимизироваить select!

Попробуйте UNION ALL вместо UNION. В этом случае будет дублирование записей, но зато не будет операции поиска пересечения

Неактивен

 

#7 11.12.2008 18:06:31

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: ПОМОГИТЕ оптимизироваить select!

Не забудьте настроить Query cache

Неактивен

 

#8 11.12.2008 18:26:22

COOLim
Участник
Зарегистрирован: 11.12.2008
Сообщений: 7

Re: ПОМОГИТЕ оптимизироваить select!

А вот еще вопрос.
Проблема заключается в таблице LINK. Может стоит попробовать создать индексы и загрузить их в память (читал про что то похожее в Вашем форуме)? Теоретически должно ускорить работу. Я пробовал создавать индекс, но меня все время пугает EXPLAIN который определяел для таблицы LINK Type = All, key = null (т.е. как я понимаю он не хочет использовать индекс). Принудително заставить использоать индекс (USE INDEX) тоже не помог.
И не подскажите какие лучше всего индексы создать по структуре данной таблицы?
Заранее Вам благодарен.

Неактивен

 

#9 11.12.2008 18:31:39

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: ПОМОГИТЕ оптимизироваить select!

Индексы у Вас и так есть и работают, судя по explain. Просто Вы выбираете все записи из Link по структуре самого запроса. В любом случае будет fulln table scan

Неактивен

 

#10 11.12.2008 19:33:19

COOLim
Участник
Зарегистрирован: 11.12.2008
Сообщений: 7

Re: ПОМОГИТЕ оптимизироваить select!

Спасибо за совет "Кэширование запросов в MySQL".
Нашел выход:

DROP TABLE IF EXIST "cache_link"

CREATE TABLE cache_link ENGINE=MEMORY
select OBJ1_ID, ID_1, OBJ2_ID, ID_2 from link
where (OBJ1_ID = 1 or OBJ1_ID = 15 or OBJ2_ID = 1 or OBJ1_ID = 15);

+ Поставил ограничения для таблицы LINK.

Но никак не могу разобраться с DROP TABLE IF EXIST "cache_link"! Во время "CREATE ..." говорит, что таблица "cache_link" существует.
Я так понимаю таблица в памяти, а ссылка на нее лежит в INFORMATION_SCHEMA.TABLES. Может ее и отдуда надо удалять?

Решение близко! Осталось чуть-чуть!

Неактивен

 

#11 11.12.2008 19:46:18

COOLim
Участник
Зарегистрирован: 11.12.2008
Сообщений: 7

Re: ПОМОГИТЕ оптимизироваить select!

И если я потом буду работать так:

CREATE TABLE cache_link ENGINE=MEMORY
select OBJ1_ID, ID_1, OBJ2_ID, ID_2 from link
where (OBJ1_ID = 1 or OBJ1_ID = 15 or OBJ2_ID = 1 or OBJ1_ID = 15);

select OBJ_1.ID, OBJ_1.FLD_1, OBJ_2.ID, OBJ_2.FLD_2
from OBJ_1, OBJ_2, cache_link TABLE_LINK
where ((OBJ_1.ID=TABLE_LINK.ID_1 and OBJ_2.ID=TABLE_LINK.ID_2)or(OBJ_1.ID=TABLE_LINK.ID_2 and OBJ_2.ID=TABLE_LINK.ID_1))

Большой получу прирост в скорости?
Т.е. самая большая таблица должна обрабатываться в памяти!

Неактивен

 

#12 11.12.2008 19:47:02

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: ПОМОГИТЕ оптимизироваить select!

См. FAQ п.2 http://sqlinfo.ru/forum/viewtopic.php?id=679
Ошибки в скрипте надо обрабатывать. У Вас синтаксическая ошибка EXIST => EXISTS

Неактивен

 

#13 11.12.2008 19:47:47

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: ПОМОГИТЕ оптимизироваить select!

COOLim написал:

Большой получу прирост в скорости?
Т.е. самая большая таблица должна обрабатываться в памяти!

Проверьте опытным путем.

Неактивен

 

#14 15.12.2008 11:37:16

COOLim
Участник
Зарегистрирован: 11.12.2008
Сообщений: 7

Re: ПОМОГИТЕ оптимизироваить select!

Привет Всем.

Решил свой поствленный вопрос следующим образом:

1. Воспользовался советом rgbeast (симметризовать таблицу link), но немного по другому. Написал запрос:
select distinct case when obj_1.id=1 and obj_2.id=2 then id_1 when obj_1.id=2 and obj_2.id=1 then id_2  end as id1,
case when obj_1.id=2 and obj_2.id=1 then id_2 when obj_1.id=1 and obj_2.id=2 then id_1  end as id2
from link where (obj_1.id=2 and obj_2.id=1) or (obj_2.id=1 and obj_1.id=2))

2. Поменял запрос на select from select (запрос из п. 1).
Соответственно для 3 и более таблиц данный способ построения запроса возвращаяет таблицу вида:
ID1      ID2      ID3     ...   IDN
1         2          3        ...    N   
...        ...        ...       ...    ...

3. И в самом конце в условии where поставил ограничение
OBJ_1.ID = ID1,  OBJ_2.ID = ID2, ..., OBJ_N.ID = IDN

После этого запрос для 4 таблиц (суммарно около 1 000 000 записей) выполняется порядка 5-10 сек.
Подскажиет, пожалуйста, как можно еще ускорить скорость выполнения запроса.

PS Если кому будет интересно, могу выложить запрос для 4 таблиц.

PSS Да, вот еще, скажите уважаемые ГУРУ, можно ли полностью доверяться EXPLAIN? Изучил всю информация с http://www.mysql.ru/docs/man/EXPLAIN.html и немного не понимаю вот такого случая:
Type = All, rows = 350 000, table = link таких строк 5 и более и запрос вылетает за 5 сек. (то, что сейчас получилось)
а бывает
Type = All, rows = 350 000, table = link таких строк 2 и более и запрос может выполнятся до 20 мин. (то, что было изначально)
В документации написано: "Существует неплохой способ определить, насколько хорошим является тип связывания. Для этого нужно перемножить все значения столбца rows, выводимого командой EXPLAIN. Результатом будет грубая оценка того, сколько строк должен просмотреть MySQL для выполнения запроса."
Два запроса разные. Анализирую по EXPLAIN.
В чем беда?

Всем большое спасибо за участие!

Неактивен

 

#15 15.12.2008 14:12:27

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: ПОМОГИТЕ оптимизироваить select!

EXPLAIN не всегда достоверно знает сколько строк будет в ответе. Он делает оценку на основании статистической информации о ключе.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson