Два SQL-запроса с различными ограничениями смещения выполняют разное время [дубликат]

request.cookies является dict, поэтому:

if 'country' in request.cookies:
    # do something
else:
    # do something else
123
задан Brendan Long 27 March 2013 в 22:25
поделиться

5 ответов

Нормально, что более высокие смещения замедляют запрос вниз, так как запрос должен отсчитывать первые записи OFFSET + LIMIT (и брать только LIMIT из них). Чем выше это значение, тем дольше выполняется запрос.

Запрос не может перейти к OFFSET, потому что, во-первых, записи могут иметь разную длину, и, во-вторых, могут быть пробелы, удаленные записей.

Предполагая, что id является PRIMARY KEY таблицы MyISAM, вы можете ускорить его, используя этот трюк:

SELECT  t.*
FROM    (
        SELECT  id
        FROM    mytable
        ORDER BY
                id
        LIMIT 10000, 30
        ) q
JOIN    mytable t
ON      t.id = q.id

См. эту статью:

138
ответ дан Quassnoi 18 August 2018 в 14:08
поделиться
  • 1
    MySQL "ранний поиск строк" поведение было ответом, почему он так долго говорит. По трюку, который вы предоставили, привязаны только сопоставленные идентификаторы (по индексу напрямую), сохраняя ненужные строки поиска слишком большого количества записей. Это сделал трюк, ура! – Rahman 27 December 2010 в 16:08
  • 2
    @harald: что именно вы подразумеваете под «не работает»? Это чистое улучшение производительности. Если индекс ORDER BY отсутствует, или индекс охватывает все поля, которые вам нужны, вам не нужно это обходное решение. – Quassnoi 24 November 2011 в 20:13
  • 3
    @ f055: ответ говорит «ускорить», а не «мгновенно». Вы прочитали первое предложение ответа? – Quassnoi 7 August 2012 в 18:41
  • 4
    Можно ли запустить что-то подобное для InnoDB? – NeverEndingQueue 27 May 2015 в 15:17
  • 5
    @aurora - трюк будет замедляться, если вам придется сканировать так много индекса на id, что «трюк» становится медленным. Реальное «исправление» означает «запомнить, где вы остановились». – Rick James 6 July 2015 в 21:05

Отнимающая много времени часть двух запросов извлекает строки из таблицы. Логически говоря, в версии LIMIT 0, 30 необходимо извлечь только 30 строк. В версии LIMIT 10000, 30 оценивается 10000 строк и возвращается 30 строк. Может быть какая-то оптимизация может быть выполнена моим процессом чтения данных, но рассмотрим следующее:

Что делать, если в запросах есть предложение WHERE? Механизм должен возвращать все строки, которые квалифицируются, а затем сортировать данные и, наконец, получать 30 строк.

Также рассмотрите случай, когда строки не обрабатываются в последовательности ORDER BY. Все квалификационные строки должны быть отсортированы для определения возвращаемых строк.

5
ответ дан bobs 18 August 2018 в 14:08
поделиться
  • 1
    просто интересно, почему он потребляет время, чтобы получить эти 10000 строк. Индекс, используемый в этом поле (id, который является первичным ключом), должен сделать поиск этих строк так же быстро, как поиск индекса PK для записи no. 10000, который, в свою очередь, должен стремиться к поиску файла для этого смещения, умноженного на длину записи индекса (т. Е. Поиск 10000 * 8 = байт без 80000 - при условии, что 8 - длина записи индекса) – Rahman 20 December 2010 в 21:00
  • 2
    @Rahman - единственный способ подсчитать прошлое 10000 строк - перешагнуть через них один за другим. Этот может включать только индекс, но все же строки индекса требуют времени для перехода. Существует no структура MyISAM или InnoDB, которая может корректно (во всех случаях) «искать»; для записи 10000. Предложение 10000 * 8 предполагает (1) MyISAM, (2) FIXED length record и (3) никогда не удаляется из таблицы. В любом случае, индексы MyISAM - это BTrees, поэтому это не сработает. – Rick James 25 January 2017 в 00:12
  • 3
    Как я уже сказал, этот ответ, по-моему, очень медленная часть - это поиск строк, а не перемещение индексов (которые, конечно же, будут складываться, но не так близко, как поиск строк на диске). Основываясь на обходных запросах, предоставленных для этой проблемы, я считаю, что поиск строк имеет тенденцию возникать, если вы выбираете столбцы вне индекса - даже если они не являются частью порядка by или where. Я не нашел причины, почему это необходимо, но, похоже, почему-то обходные пути помогают. – Gremio 28 July 2018 в 17:38

У меня была одна и та же проблема. Учитывая тот факт, что вы хотите собрать большое количество этих данных, а не определенный набор из 30, вы, вероятно, будете работать с циклом и увеличивать смещение на 30.

Итак, что вы можете сделать вместо этого :

  1. Удерживать последний идентификатор набора данных (30) (например, lastId = 530)
  2. Добавить условие WHERE id > lastId limit 0,30

Таким образом, вы всегда можете иметь смещение ZERO. Вы будете поражены улучшением производительности.

138
ответ дан Elzo Valugi 18 August 2018 в 14:08
поделиться
  • 1
    +1, этот ответ заслуживает большего – Alfie 28 July 2013 в 11:40
  • 2
    Это работает, если есть пробелы? Что делать, если у вас нет единственного уникального ключа (например, составного ключа)? – xaisoft 8 August 2013 в 18:51
  • 3
    Для всех это может быть неочевидно, что это работает только в том случае, если ваш результирующий набор сортируется по этому ключу в порядке возрастания (для нисходящего порядка работает одна и та же идея, но change & gt; lastid to & lt; lastid.) Не имеет значения, это первичный ключ или другое поле (или группа полей). – Eloff 16 September 2013 в 15:14
  • 4
    Просто обратите внимание, что ограничение / смещение часто используется в постраничных результатах, а сохранение lastId просто не возможно, потому что пользователь может перейти на любую страницу, а не всегда на следующей странице. Другими словами, смещение часто должно рассчитываться динамически на основе страницы и ограничения, а не следовать непрерывному шаблону. – Tom 28 December 2013 в 16:23
  • 5
    Я более подробно говорю о «запоминании того, где вы остановились». в mysql.rjweb.org/doc.php/pagination – Rick James 25 January 2017 в 00:14

MySQL не может перейти непосредственно к 10000-й записи (или 80000-й байт, как вы предлагаете), потому что он не может предположить, что он упакован / упорядочен как этот (или что он имеет непрерывные значения от 1 до 10000). Хотя это может быть и так на самом деле, MySQL не может предположить, что нет дыр / пробелов / удаленных идентификаторов.

Итак, как отмечали бобы, MySQL должен будет получить 10000 строк (или пройти через 10000-й записи индекс на id), прежде чем найти 30 для возврата.

EDIT: Чтобы проиллюстрировать мою точку

Обратите внимание, что хотя

SELECT * FROM large ORDER BY id LIMIT 10000, 30 

будет slow (er) ,

SELECT * FROM large WHERE id >  10000 ORDER BY id LIMIT 30 

будет fast (er) и будет возвращать те же результаты при условии отсутствия отсутствующих id s (т. е. пробелов).

13
ответ дан Riedsio 18 August 2018 в 14:08
поделиться
  • 1
    Это верно. Но поскольку он ограничен «id», почему он занимает столько времени, когда этот идентификатор находится в индексе (первичный ключ)? Оптимизатор должен напрямую ссылаться на этот индекс, а затем извлекать строки с соответствующими идентификаторами (которые поступают из этого индекса) – Rahman 27 December 2010 в 16:15
  • 2
    Если вы использовали предложение WHERE на id, оно могло бы перейти к этой отметке. Однако, если вы наложили на него лимит, упорядоченный по id, это просто относительный счетчик к началу, поэтому он должен пересекать весь путь. – Riedsio 27 December 2010 в 19:11
  • 3
  • 4
    – Pažout 20 August 2018 в 07:39
  • 5
    – mahesh kajale 9 October 2018 в 12:17

Я нашел интересный пример для оптимизации запросов SELECT ORDER BY id LIMIT X, Y. У меня 35 миллионов строк, поэтому для поиска ряда строк потребовалось 2 минуты.

Вот трюк:

select id, name, address, phone
FROM customers
WHERE id > 990
ORDER BY id LIMIT 1000;

Просто поставьте ГДЕ с последним идентификатором, который вы получили увеличить производительность. Для меня это было от 2 минут до 1 секунды:)

Другие интересные трюки здесь: http://www.iheavy.com/2013/06/19/3-ways-to-optimize- for-paging-in-mysql /

Он также работает со строками

3
ответ дан sym 18 August 2018 в 14:08
поделиться
  • 1
    это работает только для таблиц, где данные не удаляются – miro 18 April 2016 в 19:08
  • 2
    @miro Это верно только в том случае, если вы работаете в предположении, что ваш запрос может выполнять поиск на случайных страницах, что я не считаю, что этот плакат предполагает. Хотя мне не нравится этот метод для большинства случаев реального мира, это будет работать с пробелами, если вы всегда основываете его на полученном последнем идентификаторе. – Gremio 28 July 2018 в 17:44
Другие вопросы по тегам:

Похожие вопросы: