Я разрабатываю приложение для викторины, и я зациклился на том, как создать таблицу ответов.
Предположим, что у меня есть следующие таблицы:
User(user_id,...other columns) Question(question_id,user_id,...other columns) QuestionAnswers(question_id,answer_id... other columns)
Теперь, что делать с таблицей UserAnswers? Структура, которую я имею в виду, такова:
UserAnswers(user_id,question_id,answer_id,.. other columns)
Структура, которую я создал, отлично работает при запуске, но производительность начинает ухудшаться, когда я достигаю 10 миллионов строк. Учитывая мое приложение, если присутствует 10 000 вопросов, и в системе 1000 пользователей, и каждый пользователь отвечает на каждый вопрос. Я легко доберусь до 10 миллионов строк, и по мере роста числа пользователей и вопросов размер таблицы резко возрастет.
Что лучше подходит для хранения этих ответов?
Более того, я разработал систему в MySQL. Считаете ли вы, что одна и та же структура таблицы будет работать лучше в некоторых других СУБД?
mysql> explain select count(*) from user_answer where question_id = 9845; +----+-------------+-------------+------------+------+---------------+-------------+---------+-------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------------+------------+------+---------------+-------------+---------+-------+------+----------+-------------+ | 1 | SIMPLE | user_answer | NULL | ref | question_id | question_id | 4 | const | 645 | 100.00 | Using index | +----+-------------+-------------+------------+------+---------------+-------------+---------+-------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) mysql> explain select count(*) from user_answer; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ 1 row in set, 1 warning (0.00 sec) mysql> select count(*) from user_answer; +----------+ | count(*) | +----------+ | 20042126 | +----------+ 1 row in set (11 min 30.33 sec)
Общая концепция индексирования – это то, что осталось в ключе. Возьмем, к примеру, следующий ключ (независимо от того, является ли он первичным или нет)
key(a,b,c)
Для запросов, таких как
select region from myTable where c='Turkey'
вышеуказанный ключ не используется. Вы можете переносить таблицы.
Для запросов, таких как
select region from myTable where a=17 and c='Turkey'
Ключ используется до самой левой части, которая есть, так как b
не находится в запросе. Таким образом, ключ полезен, но не совсем полезен. Смысл, по крайней мере, он быстро доводит вас до сегментированных строк, но выполняет там, where
оттуда.
Позвольте мне сказать следующее: в этом запросе он не полностью использует индекс для перехода к c
. Он знает, что b
не находится в смешении запроса и не волшебным образом перепрыгивает через b
чтобы перейти к c
, полностью используя индекс. Но по крайней мере индекс частично используется.
Вот почему на тонкой ширине индекса, такой как ints и с композитами, я часто создаю второй составной индекс «идя в другую сторону», как показано в этом ответе для таблиц соедине- ния:
unique key(studentId,courseId,term), -- no duplicates allowed for the combo (note student can re-take it next term) key (courseId,studentId),
игнорировать term
для этого обсуждения. Точечное, это тонкие ints (относительно низкие накладные расходы). Второй ключ потребует дополнительных затрат. Так что это происходит за счет стоимости, которую я готов заплатить. Но для запросов, идущих в другом направлении, я закрыт. Смысл, запросы с участием courseId
без courseId
.
Заметьте, мой составной флип в приведенном выше не является звездным. Мне часто указывалось, что наличие этого, как показано, вызывает ненужные накладные расходы. В частности, для второго ключа он должен быть просто на courseId
(не составной). Если по первому ключу, по какой-то причине, у меня был term
вклинившийся во 2-е место, то это был бы верный пример.
Лучшим примером будет
key (a,b,c), key (c,b)
Вышеупомянутое, среди прочего, было бы полезно для запросов, идущих против только c
, а также b
и c
вместе. Но не только b
.
The Takeaway:
Сопротивляйтесь стремлению всплескивать новые индексы в вашу схему, глупо думая, что они будут использоваться. Особенно для не-левых столбцов, которые не встречаются в реальных и частых запросах. И, конечно же, не для тех только что упомянутых и более широких столбцов, как varchar (100) раз несколько флип в порядке по нескольким индексам. Все, что они делают потенциально, замедляет вставки и обновления и многократно увеличивает нулевые выигрыши в реальных запросах. Поэтому тщательно изучите все это.
Все варианты выбора исчисляются ценой. Только вы должны сделать это определение того, что подходит вашей системе.