Сортировка не является проблемой - на самом деле стоимость процессора и памяти для сортировки близка к нулю, поскольку Postgres имеет сортировку Top-N, где результирующий набор сканируется, сохраняя в актуальном состоянии небольшой буфер сортировки, содержащий только верхнюю часть -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'
OK. Я не знаю, сколько строк выбрано в обеих таблицах (скажет только EXPLAIN ANALYZE), но это, вероятно, важно. Знание этих цифр поможет.
Тогда мы получили наихудшее условие CROSS JOIN когда-либо:
and ST_within(ST_Centroid(A.wkb_geometry), ST_Buffer((B.wkb_geometry), 1000))
Это означает, что все строки A сопоставляются со всеми строками B (поэтому это выражение будет оцениваться большое количество раз), используя набор довольно сложных, медленных и ресурсоемких функций.
Конечно, это ужасно медленно!
Когда вы удаляете 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, поэтому сохраняйте результаты в столбце. Используйте триггер, чтобы держать их в курсе.
добавить столбцы типа BOX, которые будут кешироваться:
- Ограничительная рамка ST_Centroid (A.wkb_geometry)
- Ограничительная коробка ST_Buffer ((B.wkb_geometry), 1000)
добавить индексы в боксы
добавить тест перекрытия Box (используя оператор &&), который будет использовать индекс
оставьте свой ST_Within, который будет действовать как конечный фильтр для строк, которые проходят
Может быть, вы можете просто проиндексировать столбцы ST_Centroid и ST_Buffer ... и использовать (проиндексированный) оператор "содержит", см. Здесь:
http://www.postgresql.org/docs/8.2/static/functions-geometry.html