Как правильно индексировать таблицы, используемые в запросе с несколькими объединениями - PullRequest
0 голосов
/ 30 августа 2011

Я пытаюсь определить лучший способ проиндексировать мой запрос ниже.

До сих пор я создал составные / сгруппированные индексы для полей, используемых в соединениях, затем следовал порядок, в котором я использую фильтры предложений where.

ИЛИ, следует ли создавать отдельные индексы для полей, используемых в соединениях, и отдельные сгруппированные индексы для полей, используемых в выражениях where / group by / order by

  SELECT        [fields..]
  FROM          articles
  INNER JOIN    articles_to_geo 
    ON          articles_to_geo.article_id = articles.article_id 
  INNER JOIN    cities_whitelist 
    ON          cities_whitelist.city_id = articles_to_geo.whitelist_city_id
  INNER JOIN    cities 
    ON          cities.city_id = cities_whitelist.city_id
  INNER JOIN    articles_to_badges 
    ON          articles_to_badges.article_id = articles.article_id 
  INNER JOIN    badges 
    ON          badges.id = articles_to_badges.badge_id
  INNER JOIN    sites 
    ON          sites.id = articles.site_id
  WHERE         articles.expirydate > '2010-07-12'
  AND           articles.dateadded > '2010-08-11'
  AND           articles.status >= 6 

  AND           cities.city_id = 5794
  AND           cities.timezone = -7
  AND           cities_whitelist.published = 1      

  AND           articles_to_badges.badge_id IN (1,3,8,7)  

  ORDER BY      sites.sort_order";

например, мои таблицы статей имеют сгруппированный индекс по:

индекс 1

article_id
site_id
expirydate
status
dateadded

ИЛИ я должен иметь 2 индекса?

index 1 // используется для предложений объединения

article_id

index 2 // используется для where / order by / group by пункты

site_id
expirydate
status
dateadded

Примечание: другие мои таблицы также имеют индексы.

Любая помощь будет принята с благодарностью

Ответы [ 3 ]

1 голос
/ 30 августа 2011

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

При доступе к таблице есть 3 способа сделать это.

  • Использовать критерии фильтрации.
  • Использовать реляционные критерии из уже прочитанных строк.
  • Прочитайте всю таблицу!

Я начал с составления списка всех таблиц с критериями фильтрации и реляционными критериями.

articles

  articles.expirydate > 'somedate'
  articles.dateadded > 'somedate'
  articles.status >= someint

  articles.article_id <-> articles_to_geo.article_id
  articles.article_id <-> articles_to_badges.article_id
  articles.site_id <-> sites.id

articles_to_geo

  articles_to_geo.article_id <-> articles.article_id
  articles_to_geo.whitelist_city_id <-> cities_whitelist.city_id

cities_whitelist

  cities_whitelist.published = someint

  cities_whitelist.city_id <-> articles_to_geo.whitelist_city_id
  cities_whiltelist.city_id <-> cities.city_id

cities

  cities.city_id <-> cities_whiltelist.city_id

articles_to_badges

  articles_to_badges.badge_id in (some ids)

  articles_to_badges.article_id <-> articles.article_id
  article_to_badges.badge_id <-> badges.id

badges

  badges.id <-> article_to_badges.badge_id

sites

  sites.id <-> articles.site_id

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

Следующий лучший способ - запустить запрос с включенными параметрами:

SET STATISTICS IO ON
SET STATISTICS TIME ON

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


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

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

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

Articles (Filter)
  Articles_to_Geo (Relational by Article_Id)
    Cities_WhiteList (Relational by City_Id) (Filter)
    Cities (Relational by City_Id) (Filter)
  Articles_to_Badges (Relational by Article_Id) (Filter)
    Badges (Relational by Badge_Id)
  Sites (Relational by Article_Id)

Другой возможный заказ - сначала Города. Критерии для городов легко индексируются, и их может быть только 1 строка! При поиске статей для города и последующей фильтрации по дате следует прочитать меньше строк, чем при поиске статей по датам, а затем выполнить фильтрацию по городу.

Cities (Filter)
  Cities_WhiteList (Relational by City_Id) (Filter)
  Articles_to_Geo (Relational by City_Id)
    Articles (Relational by Article_Id) (Filter)
      Articles_to_Badges (Relational by Article_Id) (Filter)
        Badges (Relational by Badge_Id)
      Sites (Relational by Article_Id)

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

Badges (Read the Whole Table)
  Articles_to_Badges (Relational by Badge_Id) (Filter)
    Articles (Relational by Article_Id) (Filter)
      Articles_to_Geo (Relational by Article_Id)
        Cities_WhiteList (Relational by City_Id) (Filter)
        Cities (Relational by City_Id) (Filter)
    Sites (Relational by Article_Id)
0 голосов
/ 30 августа 2011

Редактировать: я удалил article_id поле из индекса статей

В старые времена системы СУБД не могли объединять индексы B-Tree в одной таблице. см. эту статью http://use -the-index-luke.com / sql / where-clause / search-for-range / index-merge-performance . Это означает, например, что если у вас есть отдельные индексы для всех столбцов статей, используемых в этом запросе, то будет использоваться только один из этих индексов.

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

Статьи

site_id
expirydate
status
dateadded

Articles_to_geo

article_id

cities_whitelist

city_id

город сайты объединены в sites.id = articles.site_id Здесь я предполагаю, что id является первичным ключом для сайтов, поэтому нет необходимости в дополнительных индексах для cities.city_id и cities.timezone, так как они все равно будут частью предиката фильтра

articles_to_badges

article_id
badge_id (or this could be a second index of type Bitmap, refer to the article above)

бейджи также присоединяется к первичному ключу, дополнительный индекс не требуется, если у вас есть уникальный индекс в поле id

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

  • и site_id
  • site_id и expirydate
  • и т.д.

Но это нельзя использовать в тех запросах, где вы указываете только

  • ExpiryDate
  • срок действия и статус
  • и т.д.
0 голосов
/ 30 августа 2011

Я бы предложил прочитать это: http://hackmysql.com/case4

Это хорошее объяснение того, когда и что индексировать.

Для начала я бы создал индексы для них:

  1. articles_to_geo.article_id
  2. cities_whitelist.city_id
  3. cities.city_id
  4. articles_to_badges.article_id
  5. articles_to_badges.badge_id
  6. badges.id
  7. sites.id

без вышеперечисленного, ваши объединения + IN () будут выполняться вечно

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