排序不是问题——事实上,排序的 CPU 和内存成本接近于零,因为 Postgres 具有 Top-N 排序,其中扫描结果集同时保持最新的小型排序缓冲区仅保存 Top-N 行.
select count(*) from (1 million row table) -- 0.17 s
select * from (1 million row table) order by x limit 10; -- 0.18 s
select * from (1 million row table) order by x; -- 1.80 s
因此,您会看到 Top-10 排序仅将 10 毫秒添加到愚蠢的快速计数(*),而对于真正的排序则更长。这是一个非常简洁的功能,我经常使用它。
好的,现在没有 EXPLAIN ANALYZE 是不可能确定的,但我的感觉是真正的问题是交叉连接。基本上,您使用以下方法过滤两个表中的行:
where (A.power_peak between 1.0 AND 100.0)
and A.area_acre >= 500
and A.solar_avg >= 5.0
AND A.pc_num <= 1000
and (A.fips_level1 = '06' AND A.fips_country = 'US' AND A.fips_level2 = '025')
and B.volt_mn_kv >= 69
and B.fips_code like '%US06%'
and B.status = 'active'
好的。我不知道在两个表中选择了多少行(只有 EXPLAIN ANALYZE 会告诉我),但这可能很重要。知道这些数字会有所帮助。
然后我们得到了有史以来最糟糕的 CROSS JOIN 条件:
and ST_within(ST_Centroid(A.wkb_geometry), ST_Buffer((B.wkb_geometry), 1000))
这意味着 A 的所有行都与 B 的所有行匹配(因此,这个表达式将被计算很多次),使用一堆非常复杂、缓慢且 CPU 密集型的函数。
当然慢得可怕!
当您删除 ORDER BY 时,postgres 刚出现(偶然?)在开始时有一堆匹配的行,输出这些行,并在达到 LIMIT 后停止。
这是一个小例子:
表 a 和 b 相同,包含 1000 行和 BOX 类型的列。
select * from a cross join b where (a.b && b.b) --- 0.28 s
这里 1000000 个框重叠(运算符 &&)测试在 0.28 秒内完成。生成测试数据集,因此结果集仅包含 1000 行。
create index a_b on a using gist(b);
create index b_b on a using gist(b);
select * from a cross join b where (a.b && b.b) --- 0.01 s
这里使用索引来优化交叉连接,速度快得离谱。
您需要优化该几何匹配。
- 添加将缓存的列:
- ST_Centroid(A.wkb_geometry)
- ST_Buffer((B.wkb_geometry), 1000)
在您的 CROSS JOIN 期间重新计算这些慢速函数一百万次是没有意义的,因此将结果存储在列中。使用触发器使它们保持最新。
也许您可以只索引 ST_Centroid 和 ST_Buffer 列...并使用(索引)“包含”运算符,请参见此处:
http://www.postgresql.org/docs/8.2/static/functions-geometry.html