繁体   English   中英

你能让postgres sql更高效吗

[英]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 questIDexcludedOptions["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 不知何故我相信一个查询更好:)。

你能帮我加快这个查询吗?

创建 function 会使其更快吗? 还是更简单?

谢谢你为我花一点时间

更新

表架构:

柱子 类型 整理 可空的 默认 贮存 统计目标 描述
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 性能调整和索引的更多信息,请参阅使用索引,卢克

其他注意事项:

  1. 不要使用char没有好处,也有很多缺点 使用varchartext
  2. 虽然 arrays 和 JSON 看起来节省了很多精力,但它们非常非常容易被滥用。 良好的模式设计没有捷径可走。 Arrays 应仅限于非常简单的列表,而 JSON 用于需要存储真正任意数据的情况。 您的所有 arrays 和 JSON 可能都应该替换为传统的列和连接表
  3. 将时间存储为 时间戳或其他日期/时间类型,而不是 integer。
  4. 不要使用json类型。 jsonb效率更高 特别是不要混合jsonjsonb ,它只会引起混淆。
  5. numeric(16,0)是主键的奇怪选择。 一个简单的bigint将使用更少的空间,更高效,并存储更多的数字。 bigserial甚至为自增主键提供了方便的大序列类型。
  6. 除非有必要解决歧义,否则不要引用表名和列名(标识符)。 SQL 标识符通常不区分大小写,但引用会使它们区分大小写,这会导致问题。
  7. 不要使用 SQL 关键字作为列名。 例如, time 对时间戳和日期使用“at”和“on”约定。 例如, created_atcreated_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM