【问题标题】:minimizing runtime of calculating several ranks (based on grades) on large sql tables, how short can it get (ms access)最小化在大型 sql 表上计算多个等级(基于等级)的运行时间,它可以得到多短(毫秒访问)
【发布时间】: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


    【解决方案1】:

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

    为什么?

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

    【讨论】:

    • 我同意这很愚蠢,但这是我必须满足的要求(我的老板想要这样,我们已经讨论了很多)。
    • 告诉你为什么我的老板希望它在运行中生成:他不希望数据库中有更多数据,如果一切都可以通过查询快速生成,我们会只需要原始的 grades_per_question 表
    • 一切都涉及权衡。如果你的老板坚持使用尽可能少的存储空间,即使它需要更多的处理能力,你应该问他是否应该继续压缩数据库服务器使用的硬盘驱动器。
    【解决方案2】:

    我刚刚看到你说只有 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 的排名速度,如果这还不够快,那么你需要查看分析器并查看它建议你创建的索引。

    【讨论】:

    • 您知道 SQL Server Express 是免费的 (microsoft.com/express/Database),您可以下载它,将数据放入其中,看看它是否能解决问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-06
    • 2021-08-25
    • 2013-05-05
    • 1970-01-01
    • 2022-06-13
    相关资源
    最近更新 更多