[英]can you make postgres sql more efficient
我正在尝试学习一些 postgres 技能来帮助我构建我的 flask 应用程序,我真的很关心性能,但我遇到了一些问题。
我在 postgres 中有下表( Sessions
):
会话ID | 其他栏目 | 静力学 |
---|---|---|
BDzQDeGr | * | {"excludedOptions": {"questID": ["optID", "optID2"]}} |
注意:静态是一个 jsonb。
我想执行一个查询,如果 questID 存在,则 append optID
到"Statics"->'excludedOptions'->'questID'
jsonb 数组,否则questID
questID
到excludedOptions
的["optID"]
作为值。
我花了最后 4 天的时间尝试通过一个查询来做到这一点,最后我做到了......
WITH ex AS
(
SELECT "Statics" -> 'excludedOptions'
FROM "Sessions"
WHERE "SessionID" = '{data["sessionId"]}'
)
UPDATE "Sessions"
SET "Statics" = jsonb_set(
"Statics",
ARRAY['excludedOptions', '{data["questionId"]}'],
array_to_json(array_remove((
SELECT
ARRAY['{data["answerId"]}'] || coalesce((
SELECT
jsonb_array_to_text_array((
SELECT value
FROM jsonb_each(( SELECT ex.* FROM ex))
WHERE key = '{data["questionId"]}'
))
), null)
), null))::jsonb,
TRUE
) WHERE "SessionID" = '{data["sessionId"]}'
注意:上面的 SQL 是 python f-string
但是当我测量执行时间时,它大约是 300-600 毫秒,这对于这个简单的操作来说是很多时间。
我希望它是一个查询 cz 不知何故我相信一个查询更好:)。
谢谢你为我花一点时间
表架构:
柱子 | 类型 | 整理 | 可空的 | 默认 | 贮存 | 统计目标 | 描述 |
---|---|---|---|---|---|---|---|
ID | 数字(16,0) | 不是 null | 主要的 | ||||
会话ID | 性格变化(8) | 不是 null | 扩展的 | ||||
标题 | 文本 | 不是 null | 扩展的 | ||||
类型 | 文本 | 不是 null | 扩展的 | ||||
资源 | 文本 | 不是 null | 扩展的 | ||||
问题 | 字符(6)[] | 不是 null | 扩展的 | ||||
跳过 | 字符(6)[] | '{}'::bpchar[] | 扩展的 | ||||
已回答 | json | '{}'::json | 扩展的 | ||||
使用提示 | 字符(6)[] | '{}'::bpchar[] | 扩展的 | ||||
最后结果 | 小字 | 0 | 清楚的 | ||||
静力学 | jsonb | '{"timer":{}, "excludedOptions":{}}'::json | 扩展的 | ||||
标记 | 字符(6)[] | '{}'::bpchar[] | 扩展的 | ||||
时间 | integer | 不是 null | 0 | 清楚的 |
解释分析:
Seq Scan on "Sessions" (cost=0.00..1.00 rows=1 width=894) (actual time=0.016..0.017 rows=1 loops=1)
Planning Time: 0.037 ms
Execution Time: 0.030 ms
您的表没有索引,因此 Postgresql 必须扫描整个表才能找到任何内容。 这就是“Seq Scan”。 您需要添加一些索引以避免表扫描并提高查询效率。
由于您正在检查WHERE "SessionID" =...
SessionID 上的索引将允许 Postgres 找到所有匹配的行,而无需扫描整个表。
有关 SQL 性能调整和索引的更多信息,请参阅使用索引,卢克。
其他注意事项:
char
,没有好处,也有很多缺点。 使用varchar
或text
。json
类型。 jsonb
效率更高。 特别是不要混合json
和jsonb
,它只会引起混淆。numeric(16,0)
是主键的奇怪选择。 一个简单的bigint
将使用更少的空间,更高效,并存储更多的数字。 bigserial
甚至为自增主键提供了方便的大序列类型。time
。 对时间戳和日期使用“at”和“on”约定。 例如, created_at
或created_on
。Schwern 给出的性能提示是绝对有效的。 但是,您的 UPDATE 语句可以大大简化 - 至少如果我正确理解了您的问题。
update sessions
set statistics =
case
when statistics -> 'excludedOptions' ? 'questID'
then jsonb_set(statistics, '{excludedOptions,questID}', (statistics #> '{excludedOptions,questID}') || '["newOptId"]')
else
jsonb_set(statistics, '{excludedOptions}', '{"questID": ["newOptId"]}')
end
where session_id = ....;
如果在excludedOptions
中有一个键questID
,那么这将 append 字符串值"newOptId"
到该数组。 如果没有键questID
,它将使用单元素数组作为其值来创建。
不需要 CTE 或取消嵌套和聚合questID
的数组
sessions.session_id
应该有一个索引来加快速度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.