|
|
|
Рекурсивный Left Joit
|
|||
|---|---|---|---|
|
#18+
Здравствуйте! Есть таблица people. У каждого человека есть отец и мать. Соответственно, структура такая: Код: sql 1. 2. 3. 4. 5. 6. 7. Задача: выбрать всех предков человека: по линии отца и матери. По сути, построить родословную. Количество поколений для выборки ограничено 8. Решил решать задачу, джойня таблицу саму с собой. Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. Вроде бы все нормально, но explain выдает грусть: id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE D0 const PRIMARY PRIMARY 4 const 1 1 SIMPLE D1 range PRIMARY PRIMARY 4 NULL 2 Using where 1 SIMPLE D2 ALL PRIMARY NULL NULL NULL 562869 Range checked for each record (index map: 0x1) 1 SIMPLE D3 ALL PRIMARY NULL NULL NULL 562869 Range checked for each record (index map: 0x1) Собственно в таблице 562 869 строк. Как можно соптимизировать запрос? Можно ли выставить какие либо индексы, что бы джойны выполнялись быстрее? (Сейчас запрос занимает почти полторы секунды) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.08.2013, 20:04:38 |
|
||
|
Рекурсивный Left Joit
|
|||
|---|---|---|---|
|
#18+
vladqaЗдравствуйте! Есть таблица people. У каждого человека есть отец и мать. Соответственно, структура такая: Код: sql 1. 2. 3. 4. 5. 6. 7. Задача: выбрать всех предков человека: по линии отца и матери. По сути, построить родословную. Количество поколений для выборки ограничено 8. Решил решать задачу, джойня таблицу саму с собой. Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. Вроде бы все нормально, но explain выдает грусть: id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE D0 const PRIMARY PRIMARY 4 const 1 1 SIMPLE D1 range PRIMARY PRIMARY 4 NULL 2 Using where 1 SIMPLE D2 ALL PRIMARY NULL NULL NULL 562869 Range checked for each record (index map: 0x1) 1 SIMPLE D3 ALL PRIMARY NULL NULL NULL 562869 Range checked for each record (index map: 0x1) Собственно в таблице 562 869 строк. Как можно соптимизировать запрос? Можно ли выставить какие либо индексы, что бы джойны выполнялись быстрее? (Сейчас запрос занимает почти полторы секунды) 1. главная проблeма: "OR". Интересно что OR в Д1 пошел по РАНЖЕ. Очевидно оптимизатор учел что будет всего 2 запроса. Далее для Д2 и Д3 оптимизатор пошел на фул-скан. очевидно не зная сколько будет запросов. 2. Варинат решения: процедурка на 6-8 простых последовательных запросов выдаст результат за 5 милисекунд 3. Варинат решения -- жестко за-форсируйте ПРИМАРИ индекс на связке с Д2 и Д3. Может и пойдет 4. Вариант: Переписать СКЛ на "UNION ALL" вместо "OR" . Может получится очень громоздкий СКЛ. 5. Вариант : переделать структуру --- посмотрите FAQ по этой теме, там вроде есть алтернативные построения связок. Советую работать в порядке: 3,2,4,5. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.08.2013, 21:23:22 |
|
||
|
Рекурсивный Left Joit
|
|||
|---|---|---|---|
|
#18+
1. главная проблeма: "OR". Интересно что OR в Д1 пошел по РАНЖЕ. Очевидно оптимизатор учел что будет всего 2 запроса. Далее для Д2 и Д3 оптимизатор пошел на фул-скан. очевидно не зная сколько будет запросов. 2. Варинат решения: процедурка на 6-8 простых последовательных запросов выдаст результат за 5 милисекунд 3. Варинат решения -- жестко за-форсируйте ПРИМАРИ индекс на связке с Д2 и Д3. Может и пойдет 4. Вариант: Переписать СКЛ на "UNION ALL" вместо "OR" . Может получится очень громоздкий СКЛ. 5. Вариант : переделать структуру --- посмотрите FAQ по этой теме, там вроде есть алтернативные построения связок. Советую работать в порядке: 3,2,4,5.[/quot] Спасибо за такой основательный ответ! Попробовал второй вариант, как самый простой и понятный мне. Запрос получился такой Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. Но, к сожалению, EXPLAIN выдает все ту же грусть (да и время запроса не сократилось) Дальше рассматриваю вариант с хранимкой, но, мне кажется, что там не отделаться 6-8 простых запросов, т.к. для выборки всего дерева таким образом придется на каждом поколении для каждого человека придется выбирать его предков с глубиной 1. То есть получится, что в зависимости от требуемой глубины нужно: 1 поколение - 1 запрос 2 поколения 1 + 2 запроса 3 поколения 1 + 2 + 4 запроса 4 поколения 1 + 2 + 4 + 8 запросов 6 поколений .... 8 поколений 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 запросов Или я не очень понял Вашу мысль? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.08.2013, 22:58:48 |
|
||
|
Рекурсивный Left Joit
|
|||
|---|---|---|---|
|
#18+
vladqa, так вы определитесь, сколько у вас будет поколений? Изначальный запрос был на 3 уровня вверх, ну и в процедуре будет максимум, кажется, полтора десятка запросов (папу и маму ишем в двух отдельных запросах.). По индексу то будет несколько милисекунд на всё-про-всё. А 8 уровней в процедуре -- ну, навскидку, полтыши запросов по индексу - полюбому лучше чем 7 фулсканов. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.08.2013, 23:09:46 |
|
||
|
Рекурсивный Left Joit
|
|||
|---|---|---|---|
|
#18+
так вы определитесь, сколько у вас будет поколений? Изначальный запрос был на 3 уровня вверх Изначально написал в задаче, что до 8 поколений включительно =) Просто в примере привел запрос на выборку 3 поколений, чтобы легче было понять суть запроса. Извиняюсь, если таким образом ввел в заблуждение. Да, получится около полтыщи, если маму и папу отдельно выбирать. У меня нет большого опыта в оптимизации производительности СУБД и, поэтому, меня смущает эта цифра =( Не убьется ли сервер при хоть какой-либо нагрузке? (конечно я понимаю, что с теми фулсканами что есть, он убьется гораздо быстрее) Правильно ли я понимаю, что выходит так, что mysql не сможет использовать индексы в запросе с рекурсивным join и это никак не побороть? Ну и вариант с UNION ALL я не совсем понял, если честно. А что касается 5. Вариант : переделать структуру --- посмотрите FAQ по этой теме, там вроде есть алтернативные построения связок. Не могли бы "ткнуть носом", в какое именно faq? Читал про хранение древовидных структур, знаю про всякие nested sets, но не смог применить у себя =( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.08.2013, 23:25:31 |
|
||
|
Рекурсивный Left Joit
|
|||
|---|---|---|---|
|
#18+
vladqa, 1. переписать select * from t where id = x OR id = Y (в этом случае чаше будет фулскан) можно так, 100% сохранив функциональность: select * from t where id = x union all select * from t where id = y (при этом случае индекс будет почти 100%). 2. Для справки, чисто для прикидки, единичный запрос по индексу будет примерно доли милисекунды на средненьком железе. т.е. 500 отдельных запросов займет десятки милисекунд (если из процедуры). Каждый фулскан добавит, ну скажем по полсекунде, т.е 4-5 секунд на 8-етажный жоинт (фулскан без индексов). Т.е. разница в 2-3 порядка. 3. Идеи для алтернативных структур и алтернативных запросах посмотрите вот в этой FAQ теме: http://www.sql.ru/forum/684437/faq-drevovidnye-struktury-sredstvami-mysql-ili-roman-stendalya-krasnoe-i-chernoe ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.08.2013, 05:14:14 |
|
||
|
Рекурсивный Left Joit
|
|||
|---|---|---|---|
|
#18+
javajdbc, пытаюсь попробовать UNION ALL и не могу понять, куда его впихнуть. У меня же условие OR было в конструкции ON. А как переписать запрос на UNION ALL, не понятно. Не могли бы натолкнуть на мысть? Попробовал также вариант с выборкой родителей как раз с помощью union ALL: SELECT D.id as D_id, D.name as D_name, D.mother_id AS D_mother_id, D.father_id as D_father_id FROM people AS D WHERE D.id = :mother_id UNION ALL SELECT D.id as D_id, D.name as D_name, D.mother_id AS D_mother_id, D.father_id as D_father_id FROM people AS D WHERE D.id = :father_id Работает, конечно, быстрее: ~0.2-0.5 секунды Но у меня же требуемая вложенность для каждого запроса известна, очень хотелось бы все таки сконструировать пусть и большой. но все же один запрос ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.08.2013, 22:32:00 |
|
||
|
Рекурсивный Left Joit
|
|||
|---|---|---|---|
|
#18+
vladqa, 1. SELECT D.id as D_id, D.name as D_name, D.mother_id AS D_mother_id, D.father_id as D_father_id FROM people AS D WHERE D.id = :father_id Этот селект обязан отработать за доли милисекунды 2. да, похоже не будет номального СКЛ-а использую union all для нескольких уровней 3. Сделайте линейную процедуру. будет проше и понятно. 4. сделайте рекурсивную процедуру -- будет красиво (но не знаю, допускает ли mysql рекурсию?) 5. ну или ждите специалистов по деревьям, тут люди есть, но они как-то не активны... СПЕЦИАЛИСТЫ, ау!!!, помогите вырастить дерево! :-) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.08.2013, 23:51:55 |
|
||
|
Рекурсивный Left Joit
|
|||
|---|---|---|---|
|
#18+
vladqaочень хотелось бы все таки сконструировать пусть и большой. но все же один запросзачем? javajdbcСделайте линейную процедуру. будет проше и понятно.+1 понабивать всех предков во временную таблицу, на конечном этапе сделать select distinct из неё, вот и всё. javajdbcпомогите вырастить дерево! :-)а это не дерево :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.08.2013, 06:09:21 |
|
||
|
|

start [/forum/topic.php?fid=47&msg=38363940&tid=1836261]: |
0ms |
get settings: |
5ms |
get forum list: |
10ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
35ms |
get topic data: |
8ms |
get forum data: |
2ms |
get page messages: |
45ms |
get tp. blocked users: |
1ms |
| others: | 205ms |
| total: | 315ms |

| 0 / 0 |
