我正在使用 Postgres,我看到两列上的 order by 与仅一列上的 order by 相比,我的查询慢了几个数量级。我正在考虑的表中有大约 2950 万行。
以下是三个不同查询的结果:
仅在 id 上订购:
EXPLAIN ANALYZE SELECT "api_meterdata"."id", "api_meterdata"."meter_id", "api_meterdata"."datetime", "api_meter"."id" FROM "api_meterdata" INNER JOIN "api_meter" ON ( "api_meterdata"."meter_id" = "api_meter"."id" ) ORDER BY "api_meterdata"."id" DESC LIMIT 100;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.44..321.49 rows=100 width=20) (actual time=0.407..30.424 rows=100 loops=1)
-> Nested Loop (cost=0.44..94824299.30 rows=29535145 width=20) (actual time=0.402..30.090 rows=100 loops=1)
Join Filter: (api_meterdata.meter_id = api_meter.id)
Rows Removed by Join Filter: 8147
-> Index Scan Backward using api_meterdata_pkey on api_meterdata (cost=0.44..58053041.74 rows=29535145 width=16) (actual time=0.103..0.867 rows=100 loops=1)
-> Materialize (cost=0.00..2.25 rows=83 width=4) (actual time=0.002..0.144 rows=82 loops=100)
-> Seq Scan on api_meter (cost=0.00..1.83 rows=83 width=4) (actual time=0.008..0.153 rows=83 loops=1) Planning time:
0.491 ms Execution time: 30.701 ms (9 rows)
仅在日期时间订购:
EXPLAIN ANALYZE SELECT "api_meterdata"."id", "api_meterdata"."meter_id", "api_meterdata"."datetime", "api_meter"."id" FROM "api_meterdata" INNER JOIN "api_meter" ON ( "api_meterdata"."meter_id" = "api_meter"."id" ) ORDER BY "api_meterdata"."datetime" ASC LIMIT 100;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.44..321.50 rows=100 width=20) (actual time=1.245..37.054 rows=100 loops=1)
-> Nested Loop (cost=0.44..94825493.68 rows=29535313 width=20) (actual time=1.238..36.652 rows=100 loops=1)
Join Filter: (api_meterdata.meter_id = api_meter.id)
Rows Removed by Join Filter: 8148
-> Index Scan using api_meterdata_datetime_index on api_meterdata (cost=0.44..58054026.95 rows=29535313 width=16) (actual time=0.851..1.501 rows=100 loops=1)
-> Materialize (cost=0.00..2.25 rows=83 width=4) (actual time=0.002..0.172 rows=82 loops=100)
-> Seq Scan on api_meter (cost=0.00..1.83 rows=83 width=4) (actual time=0.013..0.192 rows=83 loops=1)
Planning time: 0.483 ms
Execution time: 37.340 ms
(9 rows)
在日期时间和 id 上按顺序排列:
EXPLAIN ANALYZE SELECT "api_meterdata"."id", "api_meterdata"."meter_id", "api_meterdata"."datetime", "api_meter"."id" FROM "api_meterdata" INNER JOIN "api_meter" ON ( "api_meterdata"."meter_id" = "api_meter"."id" ) ORDER BY "api_meterdata"."datetime" ASC, "api_meterdata"."id" DESC LIMIT 100;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=3064122.28..3064122.53 rows=100 width=20) (actual time=146772.167..146772.372 rows=100 loops=1)
-> Sort (cost=3064122.28..3137955.90 rows=29533446 width=20) (actual time=146772.164..146772.242 rows=100 loops=1)
Sort Key: api_meterdata.datetime, api_meterdata.id
Sort Method: top-N heapsort Memory: 32kB
-> Hash Join (cost=2.87..1935375.21 rows=29533446 width=20) (actual time=0.394..113349.364 rows=29535544 loops=1)
Hash Cond: (api_meterdata.meter_id = api_meter.id)
-> Seq Scan on api_meterdata (cost=0.00..1529287.46 rows=29533446 width=16) (actual time=0.220..47537.991 rows=29535544 loops=1)
-> Hash (cost=1.83..1.83 rows=83 width=4) (actual time=0.160..0.160 rows=83 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 3kB
-> Seq Scan on api_meter (cost=0.00..1.83 rows=83 width=4) (actual time=0.005..0.071 rows=83 loops=1)
Planning time: 0.290 ms
Execution time: 146772.500 ms
(12 rows)
这是表上的索引:
SELECT * FROM pg_indexes WHERE tablename = 'api_meterdata';
schemaname | tablename | indexname | tablespace | indexdef
------------+---------------+----------------------------------------------+------------+-----------------------------------------------------------------------------------------------------
---------------
public | api_meterdata | api_meterdata_meter_id_36fe63013b50049f_uniq | | CREATE UNIQUE INDEX api_meterdata_meter_id_36fe63013b50049f_uniq ON api_meterdata USING btree (meter
_id, datetime)
public | api_meterdata | api_meterdata_pkey | | CREATE UNIQUE INDEX api_meterdata_pkey ON api_meterdata USING btree (id)
public | api_meterdata | api_meterdata_f7a5de1d | | CREATE INDEX api_meterdata_f7a5de1d ON api_meterdata USING btree (meter_id)
public | api_meterdata | api_meterdata_datetime_index | | CREATE INDEX api_meterdata_datetime_index ON api_meterdata USING btree (datetime)
(4 rows)
我可以看到这是花费时间最长的排序步骤。但不确定为什么。