Лучшие практики для работы с индексами базы данных [закрыто]

17

Каковы некоторые DO и DONT для повышения производительности базы данных с помощью индекса?

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

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

Нажмите Upvote
источник
3
профиль, профиль, профиль
GrandmasterB
1
См. Stackoverflow.com/questions/6098616/dos-and-donts-for-indexes
Дени де Бернарди

Ответы:

15

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

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

Всякий раз, когда вы добавляете или удаляете индекс, попробуйте выполнить тест производительности, чтобы увидеть, как он влияет. Без этого ты стреляешь вслепую.

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

Дэвид Торнли
источник
17

Это сильно зависит от того, как вы используете ваши таблицы. Единого и простого ответа не существует.

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

Они существуют для SQL Server и Oracle . Я не знаю, есть ли у других СУБД, но я сомневаюсь, что они не предоставляют такие основные инструменты.

Несколько случайных рекомендаций:

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

Последний совет : если производительность БД действительно важна для вашего проекта, наймите специалиста. Это то, что я сделал.


источник
2
+1 за указатели на комбинации столбцов. Индексы столбцов aи bэто не то же самое , как индекс на (a, b). Последний почти так же хорош, как индекс aдля ускорения запросов с условием a, значительно лучше для запросов с условиями aи bи бесполезен для запросов в bодиночку. (Большинство баз данных не будут использовать его. Oracle будет использовать его, но не получает от него того, что регулярно делает.)
btilly
2
+1, добавил бы «научиться читать планы запросов, чтобы вы знали, что индексировать»
Стивен А. Лоу
4

@Pierre 303 уже сказал это, но я скажу это снова. НУЖНО использовать индексы для комбинаций столбцов. Объединенный индекс (a, b)только для запросов медленнее, aчем индекс aодин, и намного лучше, если ваш запрос объединяет оба столбца. Некоторые базы данных могут объединять индексы в таблице aи bдо нее, но это не так хорошо, как объединенный индекс. Когда вы создаете комбинированный индекс, вы должны поместить столбец, который наиболее вероятно будет найден первым в комбинированном индексе.

Если ваша база данных поддерживает это, DO ставит индексы для функций, которые отображаются в запросах, а не в столбцах. (Если вы вызываете функцию для столбца, индексы для этого столбца бесполезны.)

Если вы используете базу данных с настоящими временными таблицами, которые вы можете создавать и уничтожать на лету (например, PostgreSQL, MySQL, но не Oracle), то ДОЛЖНЫ создавать индексы для временных таблиц.

Если вы используете базу данных, которая позволяет это (например, Oracle), СДЕЛАЙТЕ блокировку хороших планов запросов. Оптимизаторы запросов со временем изменят планы запросов. Они обычно улучшают план. Но иногда они делают это значительно хуже. Как правило, вы не заметите улучшения плана - запрос не был узким местом. Но один плохой план может разрушить загруженный сайт.

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

НЕ ИСПОЛЬЗУЙТЕ индексы для запросов, которые должны обращаться к более чем небольшой части большой таблицы. (Как мало зависит от аппаратного обеспечения. 5% - хорошее практическое правило.) Например, если у вас есть данные с именами и полом, имена являются хорошим кандидатом для индексации, так как любое данное имя представляет небольшую долю от общего количества строк. Не было бы полезно индексировать по полу, так как вам все равно придется получить доступ к 50% строк. Вы действительно хотите использовать полное сканирование таблицы вместо этого. Причина в том, что индексы обращаются к большому файлу случайным образом, что приводит к необходимости поиска диска. Диски ищут медленно. Например, недавно мне удалось ускорить часовой запрос, который выглядел следующим образом:

SELECT small_table.id, SUM(big_table.some_value)
FROM small_table
  JOIN big_table
    ON big_table.small_table_id = small_table.id
GROUP BY small_table.id

до 3 минут, переписав его следующим образом:

SELECT small_table.id, big_table_summary.summed_value
FROM small_table
  JOIN (
      SELECT small_table_id, SUM(some_value) as summed_value
      FROM big_table
      GROUP BY small_table_id
    ) big_table_summary
    ON big_table_summary.small_table_id =  small_table.id

что заставило базу данных понять, что она не должна пытаться использовать заманчивый индекс big_table.small_table_id. (Хорошая база данных, такая как Oracle, должна выяснить это сама. Этот запрос выполнялся на MySQL.)

Обновление: Вот объяснение точки поиска диска, которую я сделал. Индекс позволяет быстро определить, где находятся данные в таблице. Обычно это выигрыш, так как вы будете смотреть только на те данные, которые вам нужны. Но не всегда, особенно если вы в конечном итоге посмотрите на большое количество данных. Диски хорошо передают данные, но делают поиск медленным. Случайный просмотр данных на диске занимает 1/200 секунды. Медленная версия запроса завершилась примерно 600 000 из них и заняла около часа. (Было выполнено больше поисков, чем это, но некоторые из них привлекли кеширование.) В отличие от быстрой версии, она знала, что должна прочитать все, и передавала данные со скоростью около 70 МБ / с. Он прошел через таблицу размером 11 ГБ менее чем за 3 минуты.

btilly
источник
Привет, я смущен твоим примером. Я бы подумал, что использование индекса сделало бы вещи быстрее, не в этом ли смысл индексов? Вы говорите, что если запрос будет иметь доступ к> 5% таблицы, то наличие индекса по столбцу, по которому вы ведете поиск, замедлит работу?
Нажмите Upvote
@Click Upvote: если запрос обращается к более чем 5% (точная доля в значительной степени зависит от оборудования и данных) таблицы, быстрее не использовать индекс для этого запроса. Наличие индекса не повредит, если вы его не используете. Я обновлю более подробно, почему это так.
btilly
Полезная информация. Подробнее об этом, например, mysqlperformanceblog.com/2007/08/28/… Но мне было интересно, разве «ключ игнорирования» был не тем, что нужно сделать его подзапросом?
Инка
@Inca: я не знал о «ключе игнорирования». Я переключаю базы данных настолько, что часто бывают специфические вещи, о которых я не знаю. Судя по звукам, это будет работать, но значительно менее эффективно, чем мое окончательное решение. Разница в том, что это присоединится, затем группа, в то время как моя группа, затем присоединились. Это экономит работу при объединении, поскольку требуется объединять меньшее количество записей.
Btilly
«Хорошая база данных (например, Oracle, но не MySQL)»: пожалуйста, избегайте таких глупых рекламных вещей, особенно когда вы игнорируете тот факт, что MySQL может идеально использовать несколько индексов одновременно (отмечается «INDEX MERGE» в планах запросов) ,
Патрик Алларт
2

DO: Индексируйте те немногие поля, к которым вы обращаетесь больше всего, посредством запроса и / или сравнения.

НЕ индексируйте каждое поле в таблице, думая, что это сделает его быстрее.

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

Джоэл Этертон
источник
2

По сути, индексы ускоряют поиск, но замедляют запись и занимают место. Это компромисс, который делается.

Любое поле, которое часто используется для присоединения, поиска / сравнения или упорядочения, является кандидатом на индекс. Знать это действительно полезно, мера. Однако внешние ключи плотно соединенных таблиц с большим количеством записей (> 1000) и несколькими вставками окупятся.

Для текстовых полей вы можете индексировать часть поля (например, первые 6 символов), что ускорит ваш запрос, но уменьшит нагрузку на индексы. Полнотекстовый поиск (поиск like %substring%) требует различных методов, с которыми я не знаком, поэтому я не могу дать вам совет там.

Важная ситуация, когда индексы не помогут: вы не можете использовать индекс полных полей даты или даты и времени при поиске (/ join / order) в части даты. Индекс на date_createdне поможет вам с запросом, как select * from t where year(date_created) = 2011. В MySQL вы не можете создать указатель на часть даты. (Когда вы используете ' between' вместо того, чтобы year()использовать индекс в поле даты.)

Подробнее о MYSQL в руководстве: http://dev.mysql.com/doc/refman/5.6/en/optimization-indexes.html.

инка
источник
1

DO: Старайтесь сводить общий размер кластеризованного индекса к минимуму. Записи кластеризованных индексов будут включены в другие некластеризованные индексы, и отсюда возникает вероятность потери дискового пространства.


источник
1

Подумайте о таблице как о лексиконе, где статьи отсортированы по порядку появления (или вообще без полезного порядка), а о табличном индексе - как индекс книги к этому лексикону.

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

В отличие от книги, однако, таблица не однажды напечатана и затем неизменна. Он постоянно обновляется, и поэтому каждый индекс должен обновляться вместе с ним. Это, конечно, требует затрат времени и места, что может быть оправдано только полезностью индекса.

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

back2dos
источник