Понимание типов курсоров 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-стека.