2016-07-05 83 views
0

我正在设计一个测验应用程序,我被困在如何设计答案表。数据库设计在测验应用程序中的答案表

假设我有以下表格:

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

虽然这个问题可能不适合StackOverflow,但我很想知道答案,因为这是一个相当实际的问题 – Ben

+0

@Ben我知道它应该移到http://dba.stackexchange.com/,但是我想要更多的观众。 –

+1

@EricB。在生产中,1​​000万不是一个非常大的值,我们在单个mysql表中有250条记录,但其性能很好。你必须根据查询索引你的表格 –

回答

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

外卖:

抵制冲动飞溅新的索引到您的架构傻傻的以为他们会被使用。尤其对于在实际和频繁查询中没有找到的非最左边的列。当然,对于刚才提到的那些,以及像varchar(100)这样的更宽的列乘以多个索引中的几个翻转的顺序。他们所做的所有潜在的事情是减缓插入和更新,并且在实际查询中多次提供零性能增益。所以仔细检查一下。

所有索引选择都需要付费。只有你应该为你的系统做出正确的决定。