2016-04-29 13 views
3

Вот что у меня есть:Составной ключа VS первичного ключа + не уникальный индекс

table content : cat_id product_id data1 data2 etc.
категория не является уникальной, очевидно. Идентификаторы продуктов уникальны.

2 queries : 1 -- SELECT * WHERE cat_id = :cat - must be as quick as possible 2 -- SELECT * WHERE product_id = :prodId In second select, I can add : AND cat_id = :cat

Что более эффективным?

  • 1 - индекс (не единственный) на cat_id (хорошо для выбора 1)
  • 2 - первичный ключ product_id (уникальный -> отлично подходит для выбора 2)
  • 3 - индекс (не уникальный) на cat_id + PK на product_id (хорошо для 1 &-отдельно)
  • 4 - ограничения уникальности с композитным [cat_id + product_id] (хорошо для 1 &-вместе)
  • 5 - такое же, как 4, б ут определение композита PK
  • 6 - композитный (4 или 5) + единый индекс/PK

Для получения дополнительной информации, я буду иметь около 20 продуктов в каждой категории и много категорий (скажем 3000) - И (как это уникально в таблице) ОДИН продукт принадлежит только ОДНОЙ категории - На самом деле это не кошки и продукты, то есть для простоты объяснения;)

спасибо!

+0

Просто голова в варианте 4: если я правильно помню, MySQL может использовать первые части составного ключа. I.e .: Если вы определяете свои ключи как в варианте 4, а затем вы строите запрос с помощью WHERE cat_id = ..., MySQL может использовать индекс (не так с «WHERE product_id = ...»). http://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html – Sebastianb

+0

@Sebastianb - Спасибо, это то, что я не знаю: как создаются, и позже используется - составные клавиши двигателя. Итак, скажем, в phpMyAdmin, ORDER, в котором мы устанавливаем строки при определении составного индекса, важно? [cat_id + product_id]! = [product_id + cat_id]? Я добавил 5-й вариант. добавление композита в PK все лучше, нет? –

+0

До тех пор, пока у вас нет NULL кошек и продуктов, вы можете просто PK составной ключ, и я думаю, что все будет хорошо (проверьте здесь различия между уникальными индексами и PK: http://stackoverflow.com/questions/487314/primary -key или уникальный индекс). Однако, если вы хотите найти product_id, вы не будете использовать составной индекс, поэтому, я думаю, вам было бы лучше просто объявить product_id как PK и cat_id как индекс. – Sebastianb

ответ

5

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

SELECT * WHERE product_id = :prodId 

Это не имеет значения, если and cat_id = :cat_id становится частью запроса или не, если у вас есть тысячи cat_ids, связанные с каждым product_id.

Затем выберите индекс для cat_id. Это будет использоваться на

SELECT * WHERE cat_id = :cat 

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

Начиная с [cat_id+product_id] != [product_id+cat_id], когда дело доходит до индексирования, если у вас есть только один составной индекс, то он будет медленным.

Например, предположим, что у нас теперь есть составной индекс (cat_id, product_id) , следующий запрос не может использовать этот индекс.

SELECT * FROM tablename WHERE product_id = :prodId 

Но оба эти запросы могут использовать (cat_id, product_id) индекс

SELECT * FROM tablename WHERE cat_id = :cat_id and product_id = :prodId 
SELECT * FROM tablename WHERE cat_id = :catId 

Таким образом, в целом. Выберите 1 и 2.Но если число cat_id s невелико или есть много cat_ids, связанных с каждым product_id, выберите 4, но убедитесь, что первичный ключ также установлен.

+0

Спасибо! В настоящее время я пытаюсь это понять :) Для информации у меня будет около 20 продуктов в каждой категории и много категорий (скажем, 3000) - И один продукт принадлежит только ОДНОЙ категории - На самом деле, это не * действительно * кошки и продукты, которые были для простоты объяснения;) –

+0

Так, другими словами, всего около 600 000 строк в таблице больше всего? Вероятно, вам не нужен составной индекс для этого количества данных. – e4c5

+1

Чтобы дать вам идею, 600 000 строк с двумя столбцами, являющимися ints, будут иметь размер только 480k. mysql вообще не может использовать индекс, потому что этот объем данных может быть прочитан мгновенно – e4c5

1

Если это ваши только два запроса:

SELECT * FROM tablename WHERE cat_id = :cat_id and product_id = :prodId 
SELECT * FROM tablename WHERE cat_id = :cat_id 

и у вас есть какой-то другой способ, чтобы гарантировать, что product_id является UNIQUE, то вам нужно только:

PRIMARY KEY(cat_id, product_id) 

Он оптимален для какSELECTs.

Это лучше, чем INDEX(cat_id), потому что (1) вторичные ключи должны закончить работу с поиском PK и (2) все ряды кошек смежны, тем самым более эффективно.

product_id Если на самом деле AUTO_INCREMENT, а затем добавить

INDEX(product_id) 

Нет, вам не нужно говорить UNIQUE (если вы не склонны намеренно пытается вставить дубликат product_ids). Единственное, что требуется AI, это то, что идентификатор должен быть первым в некоторым индексом, чтобы он мог выполнять эквивалент SELECT max(id) всякий раз, когда перезагружается mysqld.

Мои рекомендации применяются независимо от размера таблицы.

Порядок размещения в WHEREне вопрос.

JOINs не требуется ничего в частности. Это немного более эффективно для JOIN на PRIMARY KEY, чем на вторичном ключе, что намного эффективнее (но все же возможно), чем на неиндексированных столбцах.

+0

Мой второй запрос (в моем исходном вопросе) может использовать cat_id в предложении WHERE. Таким образом, можно использовать «WHERE cat_id =: cat_id AND product_id =: prodId». Как вы сказали, 5-й ВАРИАНТ, похоже, наполнил все ожидания (даже для JOINs). Но только для того, чтобы быть уверенным в «смежных» и автоинкрементах: моя таблица может выглядеть как (cat/prod): 2/27, 4/34, 1/37, 2/12, 5/17, 2/68 ... - -> кошки НЕ являются примыкающими, а продукты НЕ ИИ ... вы все еще рекомендуете ВАРИАНТ 5? –

+0

С 'ENGINE = InnoDB' строки будут храниться в следующем порядке: 1/37, 2/17, 2/27, 2/68, 4/34, 5/17. И, поскольку эффективно линейно сканировать часть таблицы, вы получаете некоторое преимущество от «кластеризации»/«смежности». Если у вас также есть auto_increment, это испортит ситуацию. У вас есть хороший уникальный ключ, нет необходимости также иметь auto_increment. –

+0

_data_ (в InnoDB) хранится в порядке PK. Любой новый 'INSERT' найдет правильное (на основе PK) место в данных для хранения новой строки. То есть вы платите некоторую стоимость во время 'INSERT' и получаете выгоду во время' SELECT'. –