使用单个和快速SQL查询获取数据

时间:2009-01-19 17:11:01

标签: sql performance

我有以下数据:

ExamEntry   Student_ID     Grade
  11           1             80
  12           2             70
  13           3             20
  14           3             68
  15           4             75

我想找到所有通过考试的学生。在这种情况下,如果考试很少 那个学生参加了,我需要找到最后的结果。

所以,在这种情况下,我会让所有学生都过去了。

我可以通过一个快速查询找到它吗?我是这样做的:

  1. 查找条目列表 通过Student_ID

  2. 从数据组中选择max(ExamEntry)
  3. 查找结果:

  4. 从()中的ExamEntry数据中选择ExamEntry。

    但这非常慢 - 我得到大约1000个条目,这个2步过程需要10秒。

    有更好的方法吗?

    感谢。

8 个答案:

答案 0 :(得分:6)

如果你的查询在你的表中有1000条记录很慢,那就有问题了。 对于现代数据库系统,包含1000个条目的表被认为非常小 最有可能的是,你没有为你的桌子提供(主要)钥匙?

如果学生至少在成绩高于所需的最低要求时通过,则适当的查询将是:

SELECT 
  Student_ID
, MAX(Grade) AS maxGrade
FROM table_name
GROUP BY Student_ID
HAVING maxGrade > MINIMUM_GRADE_NEEDED

如果您确实需要最新成绩高于最低成绩:

SELECT 
  Student_ID
, Grade
FROM table_name
WHERE ExamEntry IN ( 
    SELECT 
      MAX(ExamEntry) 
    FROM table_name 
    GROUP BY Student_ID
)
HAVING Grade > MINIMUM_GRADE_NEEDED

答案 1 :(得分:1)

SELECT student_id, MAX(ExamEntry)
FROM data
WHERE Grade > :threshold
GROUP BY student_id

喜欢这个吗?

答案 2 :(得分:1)

我会假设你有一个学生表和测试表,你向我们展示的表是test_result表...(如果你没有类似的结构,你应该重新访问你的模式)< / p>

select s.id, s.name, t.name, max(r.score)
from student s
left outer join test_result r on r.student_id = s.id
left outer join test t on r.test_id = t.id
group by s.id, s.name, t.name

其中包含id的所有字段都应编入索引。

如果您的域中只有一个测试(类型)...那么查询将是

select s.id, s.name, max(r.score)
from student s
left outer join test_result r on r.student_id = s.id
group by s.id, s.name

答案 3 :(得分:1)

如前所述,索引是加速查询的强大工具。但是,索引的顺序非常重要。

按照(ExamEntry)然后(Student_ID)然后(等级)的顺序的索引将无法用于查找学生通过的考试。

如果您想要的是找到已通过的考试,那么相反顺序的索引将完全适合。这将使查询引擎能够快速识别已传递​​的检查行,并只处理这些行。

在MS SQL Server中,可以使用...

完成
CREATE INDEX [IX_results] ON [dbo].[results] 
(
    [Grade],
    [Student_ID],
    [ExamEntry]
)
ON [PRIMARY]

(我建议阅读更多关于索引的信息,看看有哪些其他选项,比如ClusterdIndexes等等)

使用该索引,以下查询可以非常快速地忽略“失败”考试,并只显示通过考试的学生...

(这假设如果你的年龄超过60岁,即使你再次参加考试并获得27分,你也算作通行证。)

SELECT
    Student_ID
FROM
    [results]
WHERE
    Grade >= 60
GROUP BY
    Student_ID

如果您确定需要最新值,那么您需要将索引的顺序更改为类似...

CREATE INDEX [IX_results] ON [dbo].[results] 
(
    [Student_ID],
    [ExamEntry],
    [Grade]
)
ON [PRIMARY]

这是因为我们感兴趣的第一件事是任何特定学生的最新ExamEntry。使用以下查询可以实现哪些...

SELECT
   *
FROM
   [results]
WHERE
   [results].ExamEntry = (
                          SELECT
                              MAX([student_results].ExamEntry)
                          FROM
                              [results] AS [student_results]
                          WHERE
                              [student_results].Student_ID = [results].student_id
                         )
   AND [results].Grade > 60

像这样的子查询可能看起来很慢,特别是因为它似乎是对[结果]中的每一行执行的。

但事实并非如此...... - 主查询和子查询都引用相同的表
- 查询引擎扫描索引中的每个唯一Student_ID
- 为该Student_ID执行子查询 - 查询引擎已经在索引的那一部分中 - 因此不需要新的索引查找

编辑:

有人评论说,在1000条记录中,索引不相关。应该注意的是,该问题表明返回了1000条记录,而不是该表包含1000条记录。对于基本查询,只要说明,我打赌表中有超过1000条记录。也许这可以澄清一下?

编辑:

我刚调查了3个查询,每个查询999条记录(333名学生各3名考试成绩)

方法1:WHERE a.ExamEntry =(SELECT MAX(b.ExamEntry)FROM results [a] WHERE a.Student_ID = b.student_id)

方法2:WHERE a.ExamEntry IN(SELECT MAX(ExamEntry)FROM结果GROUP BY Student_ID)

方法3:使用INNER JOIN而不是IN子句

发现以下时间:

Method    QueryCost(No Index)   QueryCost(WithIndex)
   1               23%                    9%
   2               38%                   46%
   3               38%                   46%

因此,无论索引如何,查询1都会更快,但索引也肯定会使方法1更快。

原因是索引允许查找,否则您需要扫描。线性定律与平方定律之间的区别。

答案 4 :(得分:1)

我已经使用了这里给出的提示,这里我发现的查询运行速度比第一个快了近3个订单(.03秒而不是10秒):

SELECT ExamEntry, Student_ID, Grade from data,
       ( SELECT max(ExamEntry) as ExId GROUP BY Student_ID) as newdata
WHERE `data`.`ExamEntry`=`newdata`.`ExId` AND Grade > 60;

全部谢谢!

答案 5 :(得分:0)

感谢您的回答!!

我认为Dems可能最接近我的需要,但我会详细说明这个问题。

  1. 只有最新成绩才算。如果学生第一次通过,再次参加并失败,他总共失败了。他/她可以参加3或4次考试,但仍然只有最后一次考试。
  2. 我使用MySQL服务器。我在Linux和Windows安装中遇到的问题。
  3. 我的数据集现在约为2K条目,并且每次新考试的速度增加~1K。
  4. 特定考试的查询也会返回~1K条目,当~1K是学生人数(由结果中的SELECT DISTINCT STUDENT_ID收到;),然后几乎全部通过,有些已经失败。

  5. 我在我的代码中执行以下查询: SELECT ExamEntry,考试中的Student_ID WHERE ExamEntry in(SELECT MAX(ExamEntry)from examams GROUP BY Student_ID)。当子查询返回大约1K个条目时,主查询似乎在循环中扫描它们,使得所有查询运行很长时间并且服务器负载为50%(Windows上为100%)。

  6. 感觉有更好的方法:-),但还是找不到它。

答案 6 :(得分:0)

select examentry,student_id,grade 
from data 
where examentry in 
  (select max(examentry) 
   from data 
   where grade > 60 
   group by student_id)

答案 7 :(得分:0)

不要使用

where grade > 60

where grade between 60 and 100

应该更快