|
|
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
Доброго времени суток всем, хотелось бы попросить у сообщества помощи, т.к. не могу понять, это баг MySQL или я что-то делаю не так. Опишу проблему. Имеется таблица (table1), которая связывается с другой (table2) с помощью LEFT JOIN. Если используется в выборке один столбец из table2, то индекс успешно используется. Код: sql 1. 2. 3. 4. 5. 6. 7. 8. idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra1SIMPLEtable1ALLNULLNULLNULLNULL49200Using where1SIMPLEtable2refPRIMARYPRIMARY4test1.table1.id1NULL Если используются два столбца из table1, то в EXPLAIN'е красуется загадочная надпись Using join buffer (Block Nested Loop) , индекс не используется и запрос выполняется нереально долго. Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra1SIMPLEtable1ALLNULLNULLNULLNULL49200Using where1SIMPLEtable2ALLPRIMARYNULLNULLNULL1Using where; Using join buffer (Block Nested Loop) Пока в качестве решения данной проблемы решил добавить второй аналогичный LEFT JOIN. Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. И теперь все работает замечательно, индексы используются. idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra1SIMPLEtable1ALLNULLNULLNULLNULL49200Using where1SIMPLEtable2refPRIMARYPRIMARY4test1.table1.id1NULL1SIMPLEtable3refPRIMARYPRIMARY4test1.table1.id1NULL Теперь назревает вопрос, это норма или баг? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.10.2015, 16:16:17 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
DLSTЕсли используются два столбца из table1 Оставь один, но не table1.id. А потом сядь и подумай... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.10.2015, 16:35:36 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
Прошу прощения, так торопился, что допустил несколько ошибок. DLSTЕсли используются два столбца из table1 Имелась ввиду таблица table2. Так же в последнем запросе допустил ошибку. Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. AkinaА потом сядь и подумай... И так весь день сижу и думаю, поэтому и спрашиваю совета у более опытных людей, что я делаю не так? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.10.2015, 16:45:36 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
Ну первое, что ты забыл - посмотреть на другие поля эксплейна. Попробуй объяснить, почему в первом запросе оптимизатор использовал первичный индекс второй таблицы, а во втором нет. И только когда поймёшь, подумай, как это связано с изменением экстры. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.10.2015, 17:15:52 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
Именно поэтому я и решил создать тут тему, чтобы понять, почему во втором случае (когда используются несколько столбцов из второй таблицы) не используется индекс? Я понимаю, что для многих мой вопрос может показаться глупым, но я действительно не понимаю, почему так происходит. И если Вам не будет сложно, хотелось бы узнать ответ на мой вопрос. И, если это нормальное поведение, как лучше решить проблему? Двумя джоинами? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.10.2015, 17:29:03 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
DLSTИменно поэтому я и решил создать тут тему, чтобы понять, почему во втором случае (когда используются несколько столбцов из второй таблицы) не используется индекс? Я понимаю, что для многих мой вопрос может показаться глупым, но я действительно не понимаю, почему так происходит. И если Вам не будет сложно, хотелось бы узнать ответ на мой вопрос. И, если это нормальное поведение, как лучше решить проблему? Двумя джоинами? На всякий случай, дайте ДДЛ обоих таблиц, всех индексов и каунты: select count(1) from table1 select count(1) from table1 where `table1`.`level` = 'test' если второе значение меньше чем 25% первого -- сделайте индекс на поле табле1.левел. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.10.2015, 18:30:50 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
AkinaНу первое, что ты забыл - посмотреть на другие поля эксплейна. Попробуй объяснить, почему в первом запросе оптимизатор использовал первичный индекс второй таблицы, а во втором нет. И только когда поймёшь, подумай, как это связано с изменением экстры. ...вы меня тоже заинтриговали... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.10.2015, 18:33:35 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
Не могу ничего понять, теперь все работает нормально. Значит все-таки был глюк MySQL? Или какая-то другая причина? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.10.2015, 18:59:07 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
DLSTНе могу ничего понять, теперь все работает нормально. Значит все-таки был глюк MySQL? Или какая-то другая причина? ...Х.З.... может статистика устарела... или действительно глюк... подождем что скажет Акина. Он сказал что понял что к чему... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.10.2015, 21:26:24 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
DLST, А что за версия MySQL ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.10.2015, 22:01:07 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
javajdbcили действительно глюк... подождем что скажет Акина. Он сказал что понял что к чему...Я, конечно, могу и ошибаться, может, и глюк. Но обращать внимание, я думаю, надо именно на различие планов. Из первой таблицы в обоих запросах используется одно, причём одно и то же, поле ID. Которое ещё к тому же и, как я вижу, не индексировано. Соответственно по всем параметрам (кроме нагрузки на диск) пофиг, сканить таблицу или любой содержащий это поле индекс (если они вообще есть) - и оптимизатор сканит таблицу, тупо using where. C этим вопросов нет. А вот со второй таблицей - любопытно. Из неё задействуются в первом запросе два поля (причём в условиях, которые интересны оптимизатору - только одно), а во втором запросе - три, причём по делу - опять одно. А разница оптимизации - принципиальная. Для первого запроса оптимизатор решил, что использовать индекс для отбора/фильтрации по одному полю, а затем обращение к таблице для получения значения второго поля - выгоднее, а потому задействовал индекс (получается индекс со стороны "много" и скан со стороны "один"), потому и экстра пуста. Для второго же он решил, что дешевле сразу читать всю таблицу, чем сначала индекс, а потом всё равно всю таблицу - поэтому индекс не задействован, а для отбора по совпадению полей двух таблиц приходится использовать join buffer, а т.к. они ещё и неиндексированные - то частичная сортировка и nested loops. В общем, если я не ошибаюсь, мы имеем дело со случаем, когда как раз незначительное изменение прогноза по объёму считываемых данных привело к радикальному изменению строимого плана запроса. Просто очень, я думаю, удачно сложилось - оптимизатор балансировал практически на острие, не сильно зная, в какую сторону падать, чтобы оптимум получился поглубже. Возможно, это и следствие особенностей наполнения или устаревшей статистика, но скорее это следствие странной структуры. Когда любое решение заведомо хреноватое, и любой чих заставляет менять решение. Добавь поле или пару байтов к размеру варчара - и планы половины запросов такого типа запросто поплывут. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.10.2015, 18:17:29 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
Akina, Да, кроме глюка, возможное обьяснение может быть в пограничном состоянии статистики и оценки размеров выборки и/или размера памяти. ...единственое, что может быть не следовало ожидать от ТС разобраться в этом вопросе самому ( 18289260 )... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.10.2015, 19:24:35 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
Не знаю... я не могу воспринять происходящее как глюк. Какие бы мы не заложили алгоритмы выбора и граничные значения статистик, влияющие на выбор - всегда существуют статистики, попадающие точно в выбранное нами пограничное значение, когда минимальное изменение критерия приводит к смене выбираемой стратегии. Это сродни тому, как написать выбор на основе условия IF x <= 2.2, и удивляться неверному выбору, когда x=2.2, хотя на самом деле где-то глубоко внутри x=2.20000001. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.10.2015, 09:11:48 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
AkinaНе знаю... я не могу воспринять происходящее как глюк. Какие бы мы не заложили алгоритмы выбора и граничные значения статистик, влияющие на выбор - всегда существуют статистики, попадающие точно в выбранное нами пограничное значение, когда минимальное изменение критерия приводит к смене выбираемой стратегии. Это сродни тому, как написать выбор на основе условия IF x <= 2.2, и удивляться неверному выбору, когда x=2.2, хотя на самом деле где-то глубоко внутри x=2.20000001. ok. возможно хинты помогли бы в случае продолжения "глюков" = "нестабильности пограничного состояния"... .....ну да ладно... новая неделя -- новые песни.... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.10.2015, 14:09:59 |
|
||
|
LEFT JOIN и Using join buffer (Block Nested Loop)
|
|||
|---|---|---|---|
|
#18+
javajdbc"глюков" = "нестабильности пограничного состояния"... Вот нехрен было делать - почти два часа пробовал воспроизвести такое пограничное состояние на приведённом примере. Как и следовало ожидать - с нулевым результатом. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.10.2015, 15:17:28 |
|
||
|
|

start [/forum/topic.php?fid=47&msg=39078948&tid=1832596]: |
0ms |
get settings: |
10ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
97ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
56ms |
get tp. blocked users: |
2ms |
| others: | 237ms |
| total: | 440ms |

| 0 / 0 |
