1

几个星期以来,我一直被相当著名的按年级排名学生的问题所困扰,虽然我学到了很多,但我仍然没有解决我的问题(排名已生成,但过程太慢) :

我有一个大表(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 并在类似的时间内将这些排名插入到表中这里使用的表?

另外,我很想看到一个高效的排名算法列表,这样即使我不能快速完成所有事情,我也可以尽可能地改进它。

4

2 回答 2

1

我可以一次生成所有排名,让用户可以非常快速地访问所有数据,但我的想法是一切都应该即时计算。

为什么?

为什么要一遍又一遍地重新生成相同的数据?最好在数据发生变化时生成这些统计信息,然后每隔一段时间查看一次。每当有人想要检查某事时,重做你已经完成的工作是愚蠢的。

于 2010-01-25T20:12:40.290 回答
0

我刚刚看到你说只有 ms 访问权限

所以忽略这个答案——或者如果你想能够进行这种类型的电源处理,可以考虑转移到一个真正的数据库。

下面的原始答案

我无权访问您的测试数据,但运行速度有多快?

SELECT RANK () OVER (PARTITION BY [Date],[Subject] ORDER BY Grade) AS [Global Rank],
       RANK () OVER (PARTITION BY [Date],[Subject], Classroom ORDER BY Grade) AS [Rank in classroom]
FROM grades_table_per_subject

我的猜测是您将无法在 VBA 中击败 SQL Server 的排名速度,如果这还不够快,那么您需要查看分析器并查看它建议您创建的索引。

于 2010-01-25T20:22:04.863 回答