За последние 24 часа нас посетили 18043 программиста и 1651 робот. Сейчас ищут 1704 программиста ...

Работа с логом медленных запросов

Тема в разделе "MySQL", создана пользователем Deonis, 5 мар 2017.

  1. Deonis

    Deonis Старожил

    С нами с:
    15 фев 2013
    Сообщения:
    1.521
    Симпатии:
    504
    Очень маленький вопрос. Открываю файл логов медленных запросов, беру какой-нибудь запрос. В логах у него "Query_time: 4.812942". Запускаю этот же запрос PMA. Результат запроса действительно жду долго, но в конечном итоге PMA пишет "Запрос занял 0.1060 сек."
    На ум только приходит то, что время в логах - это реально затраченное время на запрос, а PMA выдает процессорное время. Это так или это какой-то баг PMA?
     
  2. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    Я бы с этим обратился на их багтрекер, пусть разрабы репу чешут. Но похоже на баг. Попробуй тот же запрос послать из "своего PHP" и замерять время самостоятельно. Чтобы удостовериться, что это не проблема твоей версии PHP. Хотя я хз, какая может быть проблема, если надо просто из двух микротаймов получить разность...
     
    Deonis нравится это.
  3. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.115
    Симпатии:
    1.244
    Адрес:
    там-сям
    Кеш. Повторно выполненный запрос может происходить намного быстрее.
    --- Добавлено ---
    Кроме того, PMA, неявно добавляет к селекту лимит, чтобы не получать лишнего. А в логе может быть запрос на вытягивание всего-всего. Или на получение "страницы" с большим смещением, что медленнее, чем добыча первой порции. Много нюансов.
     
    denis01 нравится это.
  4. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    Только это же ни на что не влияет, потому что лимит - это отсекание вывода. Уже после полного запроса.
     
    denis01 нравится это.
  5. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    И снова нет. К примеру вот: https://ruhighload.com/post/Paging+using+MySQL
     
  6. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    А ты разобрался, что там по ссылке, прежде чем ее приводить? И как формируется выборка?
    LIMIT применяется при формировании результата. Сначала БД цепляет все строки, подходящие по условию. Выборка идет по всей таблице. Иначе бы у нас не работал корректно тот же order. Потом, когда получены указатели на все подходящие строки, идет проверка доп.условий, включая LIMIT. Если LIMIT 0,20, то, БД идет по списку, отсчитывая от нулевой строки до 20, откидывая остальное. То, что она "откусила" уходит уже как результат. Если LIMIT 480000,20, то сначала БД шаг за шагом идет до 480000 строчки. Вероятно, связано с тем, что "сырой ответ" приходит не в форме массива, а в форме связного списка, чтобы экономить память и, обеспечить максимальную гибкость. Выборки из середины у таких списков - слабое место. Как таковой структуры данных нет. Есть набор объектов, хранящих ссылку на предыдущий и на следующий элемент. За счет этого их очень легко менять местами, выбрасывать и добавлять. Почти бесплатно. Но прямого доступа к произвольному элементу нет, только через перебор ссылок. И тут именно в это место и нанесен удар. Потом отсчитывается еще 20 строк, и результат уходит в ответ.

    Зачем ты это линканул - я хз. Там нет ничего про снижение нагрузки от LIMIT, зато есть про ее повышение, если использовать LIMIT криво.

    Суть в том, что это очень частое заблуждение, что LIMIT позволяет снизить нагрузку на БД, так как если указать тот же LIMIT 0,20 то запрос, якобы, охватит лишь первые 20 строк таблицы. Но это не так. Запрос охватит всю таблицу, потом ответ будет, если надо, отсортирован, сгруппирован, и усечен до 20 записей уже в самом конце, когда все запросы были выполнены. LIMIT это всего лишь уточнение, что тебе "не надо лишнего", "хватит и N строк".
     
  7. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.115
    Симпатии:
    1.244
    Адрес:
    там-сям
    Фел, я не понял, ты вроде возражаешь, а по сути повторяешь, что лимит влияет на общую скорость выборки. :)
     
  8. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Ещё раз. Order`a может и не быть, тогда БД возьмет нужное количество строк и дальше перебирать не будет, а ещё order может быть по полю с индексом и тогда опять же запрос может быть предварительно оптимизирован перед выполнением. Оно далеко не всегда выполняется в лоб, к тому же у разных движков есть свои нюансы. Короче, не хочу я с тобой спорить, Сурикат. Я просто оставил эту ссылку здесь, что бы у людей был шанс разобраться, а не уверовать в очередные "кавычки, с которыми быстрее".
     
    artoodetoo нравится это.
  9. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    Я к тому, что неважно, что там PMA добавляет. Если запрос одинаковый и в PMA и нет, то работать будет одинаково быстро. PMA не добавляет LIMITы со смещениями безумными, а его классические 0,10/20/30 на скорость влиять не будут никак. И уж всяко не настолько, чтобы это было вообще хоть сколь-нибудь ощутимо. Если в запросе сильно сдвинутый лимит выставлен, то он выставлен явно. И будет что там, что там одинаковый эффект давать, вот я о чем.

    Что по-твоему произойдет при этом запросе?
    PHP:
    1. select * from `table` where `number`>10 limit 0,20
    Ни о чем подобном вообще речь не шла. Арту сказал, что быть может дело в лимитах, выставляемых в ПМА, а я сказал, что лимиты тут не при чем. Вот и все.
     
  10. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Код (Text):
    1. EXPLAIN ANALYSE SELECT * FROM cache WHERE restored_counter > 10;
    2. Seq Scan on cache  (cost=0.00..290113.20 rows=238734 width=1314) (actual time=2.582..7899.051 rows=212575 loops=1)
    3.   Filter: (restored_counter > 10)
    4.   Rows Removed by Filter: 187445
    5. Planning time: 0.429 ms
    6. Execution time: 7994.752 ms
    7.  
    8. EXPLAIN ANALYSE SELECT * FROM cache WHERE restored_counter > 5 LIMIT 10;
    9. Limit  (cost=0.00..8.26 rows=10 width=1314) (actual time=0.024..0.076 rows=10 loops=1)
    10.   ->  Seq Scan on cache  (cost=0.00..290113.20 rows=351384 width=1314) (actual time=0.022..0.067 rows=10 loops=1)
    11.         Filter: (restored_counter > 5)
    12.         Rows Removed by Filter: 14
    13. Planning time: 0.149 ms
    14. Execution time: 0.148 ms
    Надо объяснять почему так?

    p.s. машинка загружена чуть выше максимума, индекса на поле нет. Потому такие страшные циферы )
     
  11. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    Буду рад.
    Только можно сначала то же самое, но чтоб restored_counter > 10 в обоих случаях было, а не только в одном? Чтобы чище было.
     
  12. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Всё по 10:
    Код (Text):
    1. EXPLAIN ANALYSE SELECT * FROM cache WHERE restored_counter > 10;
    2. Seq Scan on cache  (cost=0.00..290113.20 rows=238734 width=1314) (actual time=0.029..7862.609 rows=212575 loops=1)
    3.   Filter: (restored_counter > 10)
    4.   Rows Removed by Filter: 187445
    5. Planning time: 0.411 ms
    6. Execution time: 7959.414 ms
    7.  
    8. EXPLAIN ANALYSE SELECT * FROM cache WHERE restored_counter > 10 LIMIT 10;
    9. Limit  (cost=0.00..12.15 rows=10 width=1314) (actual time=0.017..0.068 rows=10 loops=1)
    10.   ->  Seq Scan on cache  (cost=0.00..290113.20 rows=238734 width=1314) (actual time=0.015..0.059 rows=10 loops=1)
    11.         Filter: (restored_counter > 10)
    12.         Rows Removed by Filter: 22
    13. Planning time: 0.132 ms
    14. Execution time: 0.104 ms
    Дык вот, давай на пальцах, т.к. голова уже у самого не варит ) Представь что ты БД, тебе сказали пройтись по таблице и найти 10 записей, у которых restored_counter > 10. Зачем тебе искать все записи? Тебе не нужна вся таблица, ты находишь первые попавшиеся десять штук, отдаешь и дальше занимаешься своими делами.

    А вот если добавить сортировку - тогда беда, ведь тебе нужны не просто все, а самые большие по значению:
    Код (Text):
    1. EXPLAIN ANALYSE SELECT * FROM cache WHERE restored_counter > 10 ORDER BY restored_counter DESC LIMIT 10;
    2. Limit  (cost=295272.16..295272.18 rows=10 width=1314) (actual time=7143.120..7143.161 rows=10 loops=1)
    3.   ->  Sort  (cost=295272.16..295868.99 rows=238734 width=1314) (actual time=7143.103..7143.127 rows=10 loops=1)
    4.         Sort Key: restored_counter DESC
    5.         Sort Method: top-N heapsort  Memory: 45kB
    6.         ->  Seq Scan on cache  (cost=0.00..290113.20 rows=238734 width=1314) (actual time=0.155..6888.190 rows=212575 loops=1)
    7.               Filter: (restored_counter > 10)
    8.               Rows Removed by Filter: 187445
    9. Planning time: 0.721 ms
    10. Execution time: 7143.405 ms
    Но всё не так плохо, если глупый программист не забыл добавить индекс. По нему ты находить сразу то что нужно:
    Код (Text):
    1. EXPLAIN ANALYSE SELECT * FROM cache WHERE restored_counter > 10 ORDER BY restored_counter DESC LIMIT 10;
    2. Limit  (cost=0.42..26.89 rows=10 width=1314) (actual time=0.036..0.072 rows=10 loops=1)
    3.   ->  Index Scan Backward using cache_restored_counter_index on cache  (cost=0.42..551942.59 rows=208538 width=1314) (actual time=0.034..0.065 rows=10 loops=1)
    4.         Index Cond: (restored_counter > 10)
    5. Planning time: 0.343 ms
    6. Execution time: 0.115 ms
    Я к тому, что все не так однозначно, большие запросы с джоинами и прочими вложенными выборками нужно рассматривать отдельно, что бы понять в каком цикле начинает тормозить, какие индексы при этом применяются, какие нет, а какие следует добавить. И не по принципу "какие поля ищу, те и воткну", а лишь то что реально ищется на данном этапе, т.к. неправильно составленные или лишние индексы будут скорее тормозить, чем ускорять. Вот такое шаманство )
     
  13. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Пока ходил в магазин, кажется понял почему мы друг друга не понимаем. Есть два предельных случая:
    1. Нам надо выбрать первые 10 записей
    2. Нам нужно выбрать последние 10 записей.
    Во втором случае нас ждет перебор всех позиций, т.к. сначала придется отсеять все что было до. И вот тогда LIMIT ни чем не поможет в плане ускорения выборки.
     
  14. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    Окей, я понял о чем ты, да, ты прав, это логично, и оптимизация тут к месту. При ордере или групбае, соответственно, ее бы уже не было.

    Итог: @Deonis, покажи запрос чтоль.
     
    romach нравится это.
  15. Deonis

    Deonis Старожил

    С нами с:
    15 фев 2013
    Сообщения:
    1.521
    Симпатии:
    504
    Увы, но я логи уже очистил. Если примерно, то там был с десяток "OR FIND_IN_SET()" + ко всему "AND product_id IN( около 200 id-шников )".
     
  16. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.115
    Симпатии:
    1.244
    Адрес:
    там-сям
    @Fell-x27не разливаясь мыслью по древу, скажу: да, дофига случаев, когда движок вынужден сделать выборку во временную таблицу, а затем что-то там фильтровать и сортировать. но

    1. глупо утверждать, что лимит никак не влияет на скорость выполнения запроса.
    2. очевидно, что PMA неявно может подставить что-то типа LIMIT 20, а никак не LIMIT 1000000, 20

    о чем мы толкуем, не потерял ли ты нить, родной?
    --- Добавлено ---
    И ещё, не забывайте про принцип неопределённости Гайзенберга. наблюдатель влияет на характеристики наблюдаемого процесса.
    Пытаясь посмотреть почему у нас запрос медленный, мы загоняем его в кеш, набираем движку статистику, тем самым ускоряя отдачу. А в слоу лог у нас лег отчет о запросе, выполненном когда-то в неблагоприятных условиях. "Удачные" разы туда не попадают по определению.
    Поэтому картинка расходится.
    --- Добавлено ---
    Хочешь посмотреть как работает запрос без кеша — делай SELECT SQL_NO_CACHE
    --- Добавлено ---
    И даже при этом картина не повторится на 100%. Потому что сервер откажется от кеширования результатов, но исходные данные могут быть "разогреты".
    http://stackoverflow.com/questions/6666631/sql-no-cache-does-not-work
     
    Fell-x27 нравится это.