Несколько индексов с одним полем против индексов с несколькими полями - PullRequest
1 голос
/ 15 марта 2012

Я знаю, что есть аналогичные вопросы о StackOverflow, но после тестирования разных индексов в моих таблицах, я думаю, что я не совсем понимаю, как работают индексы, и мне бы хотелось, чтобы кто-то мог объяснить поведение, которое я испытываю на своем производительность запросов.

Я использую этот запрос в качестве примера, я попытаюсь объяснить его подробно:

 SELECT ss1.PlayerID, ss1.Name, ss1.Series, ss1.LanesNum, ss1.Date, ss1.LeagueName, ss1.Season FROM SeriesScores ss1
          JOIN (SELECT Series, Gender, LanesNum, Bowlout, Season FROM SeriesScores
          WHERE Gender = ? AND LanesNum = ? AND Series > -1 AND Bowlout = 'No' AND Season = '2011-2012'
          ORDER BY Series DESC LIMIT 0,?) as ss2
          USING(series, gender, lanesNum, bowlout, season)
          ORDER BY ss1.Series DESC

Этот запрос используется для получения наибольшей серии боулинга в данный сезон для каждой пары дорожек в боулинг-центре для игроков мужского и женского пола.

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

По сути, я соединяю все поля, которые соответствуют тому, что возвращает внутренний SELECT. Этот внутренний SELECT возвращает лучших игроков X для данного пола и данной пары дорожек.

ИСПОЛЬЗОВАНИЕ гарантирует, что будут выбраны только те игроки, которые не участвовали в турнирах, с тем же полом, серией, номерами и сезонами, которые я ищу. Затем я упорядочиваю их по старшим и младшим сериям.

Этот запрос находится в цикле for, который запускается 12 раз для мужчин и 12 раз для женщин (12 пар дорожек в боулинг-центре) с изменением только параметров lanesNum и пола.

Затем я поместил все результаты в два разных вектора в Java, чтобы отобразить результаты в приложении (один вектор для мужчин, один для женщин).

Без каких-либо индексов для запуска всего требуется около 11 секунд, включая помещение результатов в вектор и все такое. (5,5 секунд для 12 запросов для мужчин, то же самое для женщин).

С индексом (пол, номер линии, серия) на все это уходит 0,04 секунды, что удивительно, поскольку это более чем приемлемая скорость для моих нужд.

Я использовал этот индекс, потому что это все самые важные поля, которые я использую в своем предложении WHERE, но я не понимаю, почему он так сильно ускоряет, потому что я пробовал другие вещи и использовал некоторые другие индексы, которые на самом деле сделали мои запросы МЕНЬШЕ более чем на 100%. Кроме того, мне интересно, получу ли я еще более быстрый запрос, если добавлю к этому индексу «улавливание» и «сезон».

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

Я пришел к выводу, что я не понимаю, где я должен использовать свои индексы и когда я должен использовать их в нескольких полях, или использовать несколько индексов в отдельных полях и т. Д. Кроме того, я не понимаю, как использование (неправильных) индексов может фактически ухудшить производительность.

1 Ответ

1 голос
/ 16 марта 2012

Слишком агрессивная оптимизация индекса только для одного запроса сопряжена с риском замедления других запросов (и, следовательно, реального приложения или его следующей версии). Однако давайте сделаем именно это в качестве упражнения для анализа эффективности индекса.

Индексы влияют на производительность запросов несколькими способами; их существование может полностью изменить алгоритм, который сервер баз данных будет использовать для доступа к данным. Хороший обзор - здесь , но поскольку ваш запрос прост, и у вас на самом деле очень мало соответствующих индексов в вашей базе данных (тот, который вы видите, а также автоматически созданные индексы для поддержки первичных ключей ваших таблиц) мы можем значительно упростить историю.

Хороший индекс ускоряет перекрестную ссылку на данные между таблицами. В идеале он содержит столбцы в ваших предложениях USING и WHERE, и их достаточно, чтобы большую часть времени ссылаться на уникальную строку в своей таблице. Если он содержит меньше, он все еще может использоваться сервером базы данных, но оставшиеся строки придется посещать по одному.

Отличный индекс не только делает все это, но также содержит все данные, которые вы будете выбирать из таблицы (да, это имеет смысл, когда две таблицы фактически являются одной и той же физической таблицей из-за самосоединения; Сервер базы данных по-прежнему обрабатывает, как если бы это были две разные таблицы, кстати с одинаковыми данными). Преимущество такого «полностью охватывающего индекса» состоит в том, что серверу базы данных вообще не нужно посещать свою таблицу; все столбцы доступны в индексе.

Порядок столбцов в индексе имеет значение. Особенно важно, чтобы крайний левый столбец в индексе появлялся в предложении USING или в предложении WHERE; в противном случае индекс практически невозможно использовать, так как совпадающие данные для одного поиска могут появиться во многих местах в этом индексе. Он также должен быть очень избирательным (иметь много разных значений в таблице). Сделайте несколько экспериментов сейчас, чтобы увидеть это из первых рук.

По этой причине я бы предложил вам первый индекс выбора: series, gender, lanesNum, bowlout; но ваш также очень хорош для этого запроса.

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

К вашему последнему вопросу: некоторые люди считают, что избыточные индексы только замедляют операторы UPDATE, INSERT и DELETE (потому что они несут накладные расходы на обновление индексов), но это не так просто. Поскольку сервер базы данных рассматривает несколько алгоритмов для вычисления вашего запроса (есть две логические таблицы для начала и автоматические и явные индексы для использования или не использования), он может выбрать неправильный план: индекс может выглядеть соблазнительно, не зная данных распределение в таблице, но быть очень контрпродуктивным, учитывая распределение.

На самом деле существует способ позволить серверу базы данных анализировать данные и записывать некоторую статистику, которая значительно поможет ему разумно оптимизировать ваши последующие запросы и, вероятно, избежать любых 22-секундных выполнений вашего запроса (пока вы не измените свои данные настолько статистика больше не будет соответствовать действительности). Это команда АНАЛИЗ. Выпускайте его каждый раз после изменения индексов, чтобы увидеть последующую производительность sqlite в лучшем виде. В производственной базе данных запланируйте запуск ANALYZE каждую ночь, чтобы ваша база данных постепенно не замедлялась со временем или внезапно после добавления безвредного, бесполезного индекса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...