Trong mã mẫu của bạn ở trên, chỉ mục được tạo rõ ràng NULLS LAST
và truy vấn đang chạy ngầm NULLS FIRST
(là mặc định cho ORDER BY .. DESC
) vì vậy PostgreQuery sẽ cần sắp xếp lại dữ liệu nếu sử dụng chỉ mục. Kết quả là chỉ mục thực sự sẽ làm cho truy vấn chậm hơn nhiều lần so với quét bảng (đã chậm).
rds-9.6.5 root@db1=> create table performance (id integer, installs integer, hour timestamp without time zone);
CREATE TABLE
Time: 28.100 ms
rds-9.6.5 root@db1=> with generator as (select generate_series(1,166530) i)
[more] - > insert into performance (
[more] ( > select
[more] ( > i id,
[more] ( > (random()*1000)::integer installs,
[more] ( > (now() - make_interval(secs => i))::timestamp installs
[more] ( > from generator
[more] ( > );
INSERT 0 166530
Time: 244.872 ms
rds-9.6.5 root@db1=> create index hour_idx
[more] - > on performance
[more] - > using btree
[more] - > (hour desc nulls last);
CREATE INDEX
Time: 67.089 ms
rds-9.6.5 root@db1=> vacuum analyze performance;
VACUUM
Time: 43.552 ms
Chúng ta có thể thêm một WHERE
mệnh đề trên cột giờ để sử dụng chỉ mục trở thành một ý tưởng hay - nhưng lưu ý cách chúng ta vẫn cần sắp xếp lại dữ liệu từ chỉ mục.
rds-9.6.5 root@db1=> explain select hour from performance where hour>now() order by hour desc limit 10;
QUERY PLAN
---------------------------------------------------------------------------------------------
Limit (cost=4.45..4.46 rows=1 width=8)
-> Sort (cost=4.45..4.46 rows=1 width=8)
Sort Key: hour DESC
-> Index Only Scan using hour_idx on performance (cost=0.42..4.44 rows=1 width=8)
Index Cond: (hour > now())
(5 rows)
Time: 0.789 ms
Nếu chúng tôi thêm một tường minh NULLS LAST
vào truy vấn của bạn thì nó sẽ sử dụng chỉ mục như mong đợi.
rds-9.6.5 root@db1=> explain select hour from performance order by hour desc NULLS LAST limit 10;
QUERY PLAN
-----------------------------------------------------------------------------------------------
Limit (cost=0.42..0.68 rows=10 width=8)
-> Index Only Scan using hour_idx on performance (cost=0.42..4334.37 rows=166530 width=8)
(2 rows)
Time: 0.526 ms
Ngoài ra, nếu chúng tôi bỏ (không mặc định) NULLS LAST
khỏi chỉ mục của bạn thì truy vấn sẽ sử dụng nó như mong đợi mà không cần sửa đổi.
rds-9.6.5 root@db1=> drop index hour_idx;
DROP INDEX
Time: 4.124 ms
rds-9.6.5 root@db1=> create index hour_idx
[more] - > on performance
[more] - > using btree
[more] - > (hour desc);
CREATE INDEX
Time: 69.220 ms
rds-9.6.5 root@db1=> explain select hour from performance order by hour desc limit 10;
QUERY PLAN
-----------------------------------------------------------------------------------------------
Limit (cost=0.42..0.68 rows=10 width=8)
-> Index Only Scan using hour_idx on performance (cost=0.42..4334.37 rows=166530 width=8)
(2 rows)
Time: 0.725 ms
Lưu ý rằng bạn cũng có thể thả DESC
từ chỉ mục của bạn; PostgreSQL có thể quét các chỉ mục cả về phía trước và phía sau và trên các chỉ mục một cột thường không cần thiết để đảo ngược chúng. Bạn chỉ cần cẩn thận về việc có sự kết hợp đúng thứ tự và null trước / cuối.
rds-9.6.5 root@db1=> drop index hour_idx;
DROP INDEX
Time: 3.837 ms
rds-9.6.5 root@db1=> create index hour_idx
[more] - > on performance
[more] - > using btree
[more] - > (hour);
CREATE INDEX
Time: 94.815 ms
rds-9.6.5 root@db1=> explain select hour from performance order by hour desc limit 10;
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Limit (cost=0.42..0.68 rows=10 width=8)
-> Index Only Scan Backward using hour_idx on performance (cost=0.42..4334.37 rows=166530 width=8)
(2 rows)
Time: 0.740 ms
VACUUM ANALYZE performance;
?