Понимание типов курсоров MySQL
Версия MySQL: 5.5.37-0ubuntu0.14.04.1
В настоящее время я пишу python script, который использует множество таблиц и запросов MySQL для получения результатов от инвертированного индекса, хранящегося в таблицах.
Я заметил, что выбор правильного типа Cursor в модуле python MySQLdb при выполнении запроса оказывает действительно большое влияние на производительность и задавался вопросом, может ли кто-нибудь объяснить или предоставить надежный ресурс, объясняющий, какой курсор использовать, когда.
В качестве примера, выполнение этого запроса 40 раз с SSCursor занимает 7 секунд:
SELECT Pages.PageID,
Pages.PageName,
Counter AS TermFreq,
Pages.Length,
(Counter / LOG(Length)) AS Weight
FROM Pages
INNER JOIN TermOccurrences ON TermOccurrences.PageID = Pages.PageID
INNER JOIN Terms ON TermOccurrences.TermID = Terms.TermID
WHERE TermName = %s
ORDER BY Weight DESC
LIMIT 20;
Выполнение того же запроса 40 раз с использованием курсора по умолчанию занимает 0,004 секунды.
Удаление вычисления веса (Counter/LOG (Length)) делает этот запрос быстрее выполняемым с использованием SSCursor.
Я использовал SSCursor, потому что он оказывал значительно более высокую производительность по ряду других запросов, а затем внезапно стал очень медленным для этого. Переход к стандартным курсором удивил меня, когда он выполнялся так быстро.
EDIT:
Еще несколько примеров.
Выполнение следующего с курсором по умолчанию 40 раз занимает ~ 3 секунды:
SELECT COUNT(*)
FROM Pages
INNER JOIN TermOccurrences ON TermOccurrences.PageID = Pages.PageID
INNER JOIN Terms ON TermOccurrences.TermID = Terms.TermID
WHERE TermName = %s AND Counter > 2
Запуск его с помощью SSCursor займет примерно 0,002 секунды.
Ответы
Ответ 1
MySQLdb docs упоминают, что стандартный класс Cursor использует mysql_store_result()
, тогда как SSCursor использует mysql_use_result()
", а последний должен убедитесь, что все строки были прочитаны до того, как может быть выполнен другой запрос".
Итак, это примерно mysql_store_result()
vs mysql_use_result()
.
MySQL docs упоминает, что mysql_use_result()
инициирует поиск набора результатов без фактического чтения набора результатов в клиенте, например mysql_store_result() делает. Поэтому каждая строка должна извлекаться индивидуально с помощью вызовов mysql_fetch_row()
, что, конечно, может значительно увеличиться при работе с большими таблицами.
Также в документах MySQLdb:
SSCursor: курсор на стороне сервера. Как и курсор, но использует CursorUseResultMixIn. Используйте только в том случае, если вы имеете дело с потенциально большие результирующие наборы.
Так что SSCursor
в основном хорош, если ваш результирующий набор слишком велик, чтобы сразу перемещаться по вашему клиенту.
См. также следующие вопросы:
Обратите внимание, что запрос LIMIT 20
никогда не может быть таким большим. Возможно, вам придется проверить свои КЛЮЧИ. Чтобы лучше понять, почему это может занять 7 секунд, вероятно, лучше всего включить схему db в вопрос, возможно, что-то большее для DBA-стека.