测验应用

时间:2016-07-05 13:41:27

标签: php mysql database postgresql database-design

我正在设计一个测验应用程序,但我仍然坚持如何设计答案表。

假设我有以下表格:

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)

我所做的结构在开始时效果很好,但是一旦达到1000万行,性能开始降低。考虑到我的应用程序,如果存在10,000个问题,并且系统中有1000个用户,并且每个用户回答每个问题。我将很容易达到1000万行,随着用户和问题的增长,表的大小将会急剧增长。

存储这些答案的更好方法是什么?

此外,我在MySQL中设计了系统。您认为相同的表结构在其他DBMS中会更好吗?

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)

1 个答案:

答案 0 :(得分:2)

一般的索引概念是密钥中最左边的概念。让我们以下面的密钥为例(无论是否主要不是这里的重点)

key(a,b,c)

适用于

等查询
select region from myTable where c='Turkey'

不使用上述密钥。你可以忍受一桌扫描。

适用于

等查询
select region from myTable where a=17 and c='Turkey'

该密钥最多用于最左侧部分,即a,因为b不在查询中。所以关键是有用的,但并不完全有用。这意味着,至少它可以快速将您带到已分段的a行,但从那里执行where

让我说上面的另一种方式:在该查询中,它没有完全使用索引来到c。它知道b不在查询的混合中,并且在完全使用索引时,会神奇地跳过b以获得c。但至少部分使用了索引。

这就是为什么在精简索引宽度(如整数)和复合材料上,我经常创建第二个复合索引“走另一条路”,如此answer所示为连接表:

unique key(studentId,courseId,term), -- no duplicates allowed for the combo (note student can re-take it next term)
key (courseId,studentId),

忽略term进行此讨论。重点是,那些是薄的(开销相对较低)。第二个密钥需要开销。所以它是有代价的,我愿意付出代价。但是对于向另一个方向发出的询问,我被覆盖了。含义,涉及courseId而不包含studentId的查询。

注意,我在上面的复合翻转不是一个明星。经常向我指出,如图所示,它会导致不必要的开销。特别是,对于第二个键,它应该只在courseId上(非复合键)。如果在第一把钥匙上,无论出于何种原因term楔入第二位,那么这将是一个有效的例子。

更好的例子是

key (a,b,c),
key (c,b)

除其他外,上述内容对于仅针对c以及bc的查询非常有用。但不仅仅是b

The Takeaway:

拒绝将新索引分散到您的架构中的冲动,愚蠢地认为它们将被使用。特别是对于在实际和频繁查询中未获取的非最左侧列。当然不是那些刚才提到的和更广泛的列,如varchar(100)乘以多个索引排序的几个翻转。它们所做的一切都可能会减慢插入和更新速度,并且在实际查询中提供很多次性能提升。所以仔细审查这一切。

所有索引选择都需要付出代价。只有你应该确定什么适合你的系统。