【发布时间】:2020-08-20 09:13:50
【问题描述】:
我的 Flask 应用程序中有一个 Postgres 10 数据库。我正在尝试对表上数百万行的过滤结果进行分页。问题是,paginate 方法对查询结果总数的统计完全无效。
这是带有虚拟过滤器的示例:
paginate = Buildings.query.filter(height>10).paginate(1,10)
如果执行 2 个查询,则在后台:
SELECT * FROM buildings where height > 10
SELECT count(*) FROM (
SELECT * FROM buildings where height > 10
)
--------
count returns 200,000 rows
问题在于不带子查询的原始选择的计数非常快~30ms,但分页方法将其包装到需要 ~30s 的子查询中。
冷库查询计划:
是否可以选择以高性能方式使用来自 flask-sqlalchemy 的默认分页方法?
编辑: 为了更好地理解我的问题,这里使用了我的案例中使用的真实过滤器操作,但使用了虚拟字段名称:
paginate = Buildings.query.filter_by(owner_id=None).filter(Buildings.address.like('%A%')).paginate(1,10)
所以 ORM 产生的 SQL 是:
SELECT count(*) AS count_1
FROM (SELECT foo_column, [...]
FROM buildings
WHERE buildings.owner_id IS NULL AND buildings.address LIKE '%A%' ) AS anon_1
该查询已通过以下索引进行了优化:
CREATE INDEX ix_trgm_buildings_address ON public.buildings USING gin (address gin_trgm_ops);
CREATE INDEX ix_buildings_owner_id ON public.buildings USING btree (owner_id)
问题就在于这个count函数,太慢了。
【问题讨论】:
-
您是否在
height上添加了索引? -
子查询没有理由变慢。也许它只需要从磁盘读取数据,因为它还没有在内存中。尝试
EXPLAIN (ANALYZE, BUFFERS)的查询。 -
高度的索引是存在的。
-
@jjanes 没有子查询的查询在测试时必须已经在缓存中,这就是为什么这两者之间存在差异的原因。问题是,在缓存中没有数据的情况下是否可以加快分页速度?
标签: database postgresql flask sqlalchemy flask-sqlalchemy