一般来说算法很简单:
- 从
Student 表中检索行
- 使用 ORDER BY 表达式从 #1 开始对整个结果集进行排序
- 应用 LIMIT 子句(+ 偏移量)从 #2 获得的有序结果集中获取部分行
您可以在此处阅读有关 LIMIT 的更多信息:http://www.postgresql.org/docs/9.4/static/queries-limit.html
在某些情况下,在 ORDER BY 操作(排序)期间会考虑 LIMIT 以加快查询速度,尤其是当某些索引可用于消除排序操作时。
您可以查看解释计划来检查这项工作。
假设在这个表上创建了一个索引:
create index student_mark1 on student(student_marks1);
此查询给出以下解释计划:
select * From student
order by student_marks2
limit 1;
Limit (cost=5.06..5.06 rows=1 width=178) (actual time=0.088..0.089 rows=1 loops=1)
Output: student_name, student_rollno, student_marks1, student_marks2
-> Sort (cost=5.06..5.57 rows=204 width=178) (actual time=0.088..0.088 rows=1 loops=1)
Output: student_name, student_rollno, student_marks1, student_marks2
Sort Key: student.student_marks2
Sort Method: top-N heapsort Memory: 25kB
-> Seq Scan on public.student (cost=0.00..4.04 rows=204 width=178) (actual time=0.007..0.021 rows=204 loops=1)
Output: student_name, student_rollno, student_marks1, student_marks2
你需要从下往上阅读这个计划。
第一个操作是Seq scan - 这意味着从磁盘读取所有行(整个表 - 参见actual rows = 204)。
然后执行排序操作(ORDER BY)。最后一个操作是 LIMIT 1(在计划的顶部)
将上述计划与此查询进行比较:
select * From student
order by student_marks1
limit 1;
Limit (cost=0.14..0.24 rows=1 width=178) (actual time=0.010..0.010 rows=1 loops=1)
Output: student_name, student_rollno, student_marks1, student_marks2
-> Index Scan using student_mark1 on public.student (cost=0.14..19.20 rows=204 width=178) (actual time=0.009..0.009 rows=1 loops=1)
Output: student_name, student_rollno, student_marks1, student_marks2
这里跳过了排序阶段,因为我们可以使用索引以所需的顺序检索行 (ORDER BY student_marks1 => INDEX ON Student( student_marks1 ))。
请注意最底部操作中的Actual rows = 1:`索引扫描'。
这意味着,PostgreSQL 不会扫描整个索引,而是只从索引中检索 1(第一)行,因为它知道,查询有 LIMIT 1 个子句。 (有时会说 PostgreSQL 将限制 1 子句“下推”到索引扫描操作并使用它来减少索引中扫描条目的数量。
更多关于使用索引来加速 ORDER BY 的信息你可以在这里找到:http://www.postgresql.org/docs/8.3/static/indexes-ordering.html
如果您的问题中的查询,ORDER BY 子句包含表达式 Student_Marks1+Student_Marks2,而不是简单的列。此查询的解释计划如下所示:
select *
From student
order by student_marks1 + student_marks2
limit 2;
Limit (cost=7.10..7.11 rows=2 width=178) (actual time=0.207..0.207 rows=2 loops=1)
Output: student_name, student_rollno, student_marks1, student_marks2, (((student_marks1)::numeric + student_marks2))
-> Sort (cost=7.10..7.61 rows=204 width=178) (actual time=0.205..0.205 rows=2 loops=1)
Output: student_name, student_rollno, student_marks1, student_marks2, (((student_marks1)::numeric + student_marks2))
Sort Key: (((student.student_marks1)::numeric + student.student_marks2))
Sort Method: top-N heapsort Memory: 25kB
-> Seq Scan on public.student (cost=0.00..5.06 rows=204 width=178) (actual time=0.019..0.107 rows=204 loops=1)
Output: student_name, student_rollno, student_marks1, student_marks2, ((student_marks1)::numeric + student_marks2)
但是您仍然可以通过这种方式加快创建function based index 的查询:
create index student_mark12 on student( ( student_marks1 + student_marks2) );
创建索引后,我们现在有:
Limit (cost=0.14..0.34 rows=2 width=178) (actual time=0.044..0.047 rows=2 loops=1)
Output: student_name, student_rollno, student_marks1, student_marks2, (((student_marks1)::numeric + student_marks2))
-> Index Scan using student_mark12 on public.student (cost=0.14..20.22 rows=204 width=178) (actual time=0.043..0.046 rows=2 loops=1)
Output: student_name, student_rollno, student_marks1, student_marks2, ((student_marks1)::numeric + student_marks2)
请注意,Postgre 在这种情况下使用索引,并且根据LIMIT 2 子句仅从中检索 2 个条目(实际行 = 2)。