【发布时间】:2010-01-25 20:09:30
【问题描述】:
我已经被一个相当著名的按年级排名学生的问题困扰了几个星期了,虽然我学到了很多东西,但我仍然没有解决我的问题(排名已经生成,但过程是太慢了):
我有一个大表(320,000 行),其中包含学生代码(用作标识符,而不是他们的姓名)、学生课堂、测试、测试日期、主题、问题编号和学生成绩关于那个问题。该表是计算其他所有内容的基础,它的大小使所有这些计算非常缓慢,以至于我发现我几乎在工作中破坏了这里的所有内容。
首先,关于学校的一些情报(信息很少,需要了解问题)
在学校,我们每周都会对几个科目进行测试。学校也有不同目的的教室(一个专注于数学、物理和化学,另一个专注于生物,最后一个专注于历史、葡萄牙语和地理)。但他们每周都做同样的测试。
我们要做的是计算学校每个人(不是每个教室)每个问题的标准差和每个问题的平均成绩(也适用于学校每个人),然后生成以下排名(所有他们每个日期):
-每个班级的每门学科排名(带有“原始”成绩)、考虑整个学校的每门学科排名(带有“原始”成绩)和考虑整个学校的每门学科排名(使用标准化成绩,每个问题的标准差以及每个问题的平均成绩信息)
- 与上述相同的排名,但不是每个主题,而是考虑所有主题
如您所见,在计算了平均成绩和标准差之后,我们仍然需要计算每个问题的成绩总和,并根据这些总和(实际科目/考试成绩)进行排名。我从几个方面解决了这个问题:
1) 创建了两个表,一个包含每个学生每个学科的成绩(字段:学生代码、学生课堂、考试日期、学科、成绩、标准化成绩、课堂排名、学校排名、使用标准化成绩的学校排名),另一个包含每个学生每次考试的成绩(考虑所有科目,字段:学生代码、学生课堂、考试日期、成绩、标准化成绩、课堂排名、学校排名、使用标准化成绩的学校排名)。
在这些表中插入数据大约需要 50 秒
然后,我尝试使用 SQL 进行排名,但是遇到了一些问题:
-Access 没有 ROW_NUMBER 或 RANK 函数,因此我必须使用带有 COUNT 的查询,例如(以下只是简化版本):
SELECT 1+(SELECT Count(*) FROM grades_table_per_subject t2 WHERE
t2.Grade > t1.Grade AND t1.Date=t2.Date AND t1.Subject=t2.Subject) AS [Global Rank],
1+(SELECT Count(*) FROM grades_table_per_subject t3 WHERE t3.Grade > t1.Grade AND
t3.Date=t1.Date AND t3.Subject=t1.Subject AND t3.Classroom=t1.Classroom) AS
[Rank in classroom] FROM grades_table_per_subject;
上面的查询中还有归一化成绩的排名,但我省略了。
表 grades_table_per_subject 有大约 45,000 行,这个查询在这里需要超过 15 分钟,即使有索引(尝试了许多不同的索引组合,甚至一些奇怪的组合,当我看到应该工作的那些没有工作时)。
我也尝试了 ORDER BY Count() DESC 内部选择,但我在 7 分钟后按 ctrl+break 并没有结果。
2) 在上表中添加了以下字段: 课堂排名、学校排名、学校排名使用标准化成绩
然后我尝试使用带有 DAO 的 VBA 并手动更新排名字段,运行以下代码(简化版):
Set rs = CurrentDb.OpenRecordset("SELECT Classroom, Date, Subject, Grade, [Rank in classroom] FROM
grades_table_per_subject ORDER BY Date, Classroom, Subject, Grade DESC;", dbOpenDynaset)
...
...
rs.movefirst
i=1
While Not rs.eof
'Verifies if there was a change on either one of Subject, Classroom, Date and if so:
...
i = 1
...
rs.Edit
rs![Rank in classroom]=i
rs.Update
i = i + 1
rs.movenext
Wend
rs.close
这显然只建立了一个等级(在这种情况下,每个教室的每个科目),并且只需要 3 分 10 秒。
我验证了由于表格上的写入,它需要很长时间(rs.Edit 和 rs.Update 是罪魁祸首,评论它们使整个事情在 4 秒内运行),但我需要写入表格来生成排名稍后出具访问报告。
最后:
我可以一次性生成所有排名,让用户可以非常快速地访问所有数据,但我的想法是所有内容都应该即时计算。然而,我们所取得的成就使这成为不可能。
总的来说,要问的问题如下:
- 有没有办法在 10 秒内通过 Access Query 计算上面显示的排名,或者考虑到这里使用的表的大小,使用 VBA 并在类似的时间内将这些排名插入到表中?
另外,我很想看到一个高效的排名算法列表,这样即使我不能快速完成所有事情,我也可以尽可能地改进它。
【问题讨论】:
标签: sql ms-access runtime ranking minimize