使用Postgresql和Flask SQLAlchemy提高COUNT(*)WHERE的数据库性能

使用Postgresql和Flask SQLAlchemy提高COUNT(*)WHERE的数据库性能,postgresql,flask,heroku,sqlalchemy,Postgresql,Flask,Heroku,Sqlalchemy,我有一个运行SQLAlchemy和PostgresQL的Flask应用程序,可以处理大量数据。我们在前端显示的内容之一是一个仪表板,其中包含给定组织的多个聚合统计数据。最近这个端点运行得非常慢,所以我一直在尝试优化它并提高性能 我首先对BaseQuery进行了子类化,并实现了SQLAlchemy内置的.count的更精简版本,该版本无需使用子查询即可计数 优化查询 api/dashboard.py 这无疑是朝着正确方向迈出的一步,显著减少了端点延迟。话虽如此,加载仍然需要9-15秒,因此我潜入N

我有一个运行SQLAlchemy和PostgresQL的Flask应用程序,可以处理大量数据。我们在前端显示的内容之一是一个仪表板,其中包含给定组织的多个聚合统计数据。最近这个端点运行得非常慢,所以我一直在尝试优化它并提高性能

我首先对BaseQuery进行了子类化,并实现了SQLAlchemy内置的.count的更精简版本,该版本无需使用子查询即可计数

优化查询

api/dashboard.py

这无疑是朝着正确方向迈出的一步,显著减少了端点延迟。话虽如此,加载仍然需要9-15秒,因此我潜入NewRelic,发现messages表上的一个查询仍然执行得非常糟糕。下面的屏幕截图实际上是我能找到的最好的1.5秒,但有时需要6秒

这并不奇怪,因为messages表是4090065行中最大的一行。然而,看看这个查询,它似乎尽可能的精简,即使我放弃了SQLAlchemy而只编写纯SQL。更奇怪的是,在将prod db克隆到我的本地机器并使用pgbench分析同一查询之后,该查询运行速度极快,平均延迟为86.9ms

问题 如果是最终的精简查询,请从消息中选择count*作为count_1,其中%param_1s=messages.organization_id是查询可以获得的最精简的值? 我已经找到了很多关于计数性能和提高计数性能的策略的文章,但是没有一篇是关于计数查询的。是 在我的数据库建设中,我可以做一些事情来加快它的速度 这个案子?索引等。 pgbench 86.9ms的延迟和超过6s的生产运行时间之间的差异可能是什么原因造成的?供参考 该应用程序托管在Heroku上,利用3个标准的2倍网络动态和 Postgres标准-0附加组件。
pgbench运行会不断重复请求相同的组织id,因此数据可能会被缓存。此外,可能会有更多信息的组织。因此,运行时不同并不奇怪

既然你已经读过了,我就不告诉你细节了。我看到两种选择:

使用定期刷新的物化视图:

CREATE MATERIALIZED VIEW message_count AS
SELECT organization_id, count(*) AS c
FROM messages
GROUP BY organization_id;

CREATE UNIQUE INDEX ON message_count (organization_id);
然后你会有一些陈旧的数据,但你会很快

如果需要精确计数,请将message_count设置为常规表,并向消息添加触发器,以便在修改消息时更新相应的message_count行

这将减慢消息上的数据修改速度,但如果您确实需要频繁快速地计算数据,那么这可能是值得的


pgbench运行会不断重复请求相同的组织id,因此数据可能会被缓存。此外,可能会有更多信息的组织。因此,运行时不同并不奇怪

既然你已经读过了,我就不告诉你细节了。我看到两种选择:

使用定期刷新的物化视图:

CREATE MATERIALIZED VIEW message_count AS
SELECT organization_id, count(*) AS c
FROM messages
GROUP BY organization_id;

CREATE UNIQUE INDEX ON message_count (organization_id);
然后你会有一些陈旧的数据,但你会很快

如果需要精确计数,请将message_count设置为常规表,并向消息添加触发器,以便在修改消息时更新相应的message_count行

这将减慢消息上的数据修改速度,但如果您确实需要频繁快速地计算数据,那么这可能是值得的


以下是几点想法:如果您的生产环境正在为来自许多不同用户的请求提供服务,而您的本地环境只处理来自您的请求,那么这可能会产生显著的差异。而且如果您的pgbench测试连续50次运行同一个查询,那么由于缓存的原因,第一次迭代可能会非常慢,接下来的49次迭代可能会快得多,因此这50次迭代的平均值可能会严重向下偏移。请考虑以下几点:如果您的生产环境正在处理来自许多不同用户和本地用户的请求环境只处理来自您的请求,这可能会产生重大影响。此外,如果您的pgbench测试连续50次运行同一查询,那么由于缓存的原因,第一次迭代可能会非常慢,接下来的49次迭代可能会快得多,因此这50次迭代的平均值可能会严重向下偏移。感谢Laurenz。物化视图建议看起来非常酷。我得试试。谢谢Laurenz。物化视图建议看起来很酷。我得试试。
CREATE MATERIALIZED VIEW message_count AS
SELECT organization_id, count(*) AS c
FROM messages
GROUP BY organization_id;

CREATE UNIQUE INDEX ON message_count (organization_id);