几个星期以来,我一直被一个相当有名的按年级排列学生的问题困扰着,虽然我学到了很多,但我仍然没有解决我的问题(排名已经生成,但过程太慢):
我有一个大表(32万行),其中包含学生代码(用作标识符,而不是它们的名字)、学生教室、考试、考试日期、主题、问题编号和学生在该问题上的成绩。这张表是所有其他计算的基础,它的大小使得所有这些计算都非常慢,以至于我发现我在这里工作时几乎把所有东西都打破了。
首先,学校的一些情报(非常少的信息,需要了解问题)。
在这所学校里,我们每周有几门科目的考试。学校也有着不同的教学目的(一个是数学、物理和化学,另一个是生物学,最后一个是历史、葡萄牙语和地理)。但他们每周都做同样的测试。
我们要做的是计算学校里每个人(不是每个教室)的每个问题的标准差和每个问题的平均分数(也是学校里的每个人),然后生成以下等级(所有这些都是按日期计算):
每堂课的-Rank (带“原始”分数),每门学科考虑整个学校的等级(有“原始”分数),每门学科考虑整个学校的等级(使用标准化的年级,每个问题的标准差和每个问题信息的平均分数)
-The与上面提到的排名相同,但不是每个学科,而是考虑所有的科目。
正如你所看到的,在计算平均分数和标准差之后,我们仍然需要计算每个问题的分数和,并根据这些总和(实际的科目/考试成绩)进行排名。我从几个方面解决了这个问题:
1)创建了两个表,一个是每个科目的年级(字段:学生代码、学生课堂、测试日期、主题、年级、归一化年级、课堂排名、学校排名、学校等级,另一个表是每个学生考试的分数(所有科目都考虑到了所有科目:学生代码、学生课堂、考试日期、年级、归一化年级、教室排名、学校排名、学校等级使用标准化成绩)。
在这些表中插入数据大约需要50秒。
然后,我尝试使用SQL进行排序,但是遇到了一些问题:
-Access没有ROW_NUMBER或秩函数,因此我不得不使用有计数的查询,比如(下面是一个简化的版本):
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分钟,即使使用索引(尝试了许多不同的索引组合,甚至一些奇怪的组合,当我看到应该工作的那些没有工作)。
我还试着按Count() DESC内部选择进行排序,但是7分钟后我点击了ctrl+break,没有结果。
2)在上表中添加了以下字段:课堂排名、学校排名、使用标准化成绩的学校排名
然后,我尝试在DAO中使用VBA并手动更新Rank字段,运行以下代码(简化版本):
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秒内运行),但我需要写入表的级别在稍后生成访问报告。
最后:
我可以生成所有的队伍一次,让用户快速访问所有的数据,但想法是,一切都应该是实时计算的。然而,我们所取得的时代使得这不可能实现。
总的来说,要提出的问题如下:
-Is有一种方法可以通过10秒以下的访问查询计算上面显示的排名,或者使用VBA并计算--考虑到这里使用的表的大小,可以在类似的时间内将这些级别插入到表中?
另外,我希望看到一个高效的排名算法列表,这样即使我不能快速完成所有事情,我也可以尽可能地改进它。
发布于 2010-01-25 20:12:40
i可以一次生成所有的级别,并为用户快速访问所有数据提供方法,但其思想是,所有的数据都应该实时计算。
为什么?
为什么要一次又一次地重新生成相同的数据呢?最可取的做法是在数据变化时生成这些统计数据,然后每隔一次查找一次。每当有人想要检查某件事时,重新做你已经做过的工作就是愚蠢的。
发布于 2010-01-25 20:22:04
我刚看到你说ms access只有
所以忽略这个答案--或者考虑移动到一个真正的DB,如果你想要做这种类型的电源处理。
原来的答案在下面
我无法访问您的测试数据,但是运行速度有多快?
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服务器的排名速度,如果速度不够快,那么您需要查看分析器,看看它建议您创建哪些索引。
https://stackoverflow.com/questions/2135252
复制相似问题