per*_*alt 13 postgresql json postgresql-performance jsonb
我正在尝试加快对 PostgreSQL 数据库中存储的一些 json 数据的查询速度。我继承了一个应用程序,该应用程序查询一个名为 的 PostgreSQL 表,该data
表带有一个名为 的字段value
,其中值是类型为 json 的 blob jsonb
。
它大约有 300 行,但从 5 个 json 元素中选择此数据需要 12 秒。json blob 有点大,但我需要的数据都在 json 嵌套的顶层(如果有帮助的话)。
我尝试添加索引,CREATE INDEX idx_tbl_data ON data USING gin (value);
但这没有帮助。我应该使用不同的索引吗?长期愿景是重写应用程序以将数据移出 json,但由于应用程序其他部分的复杂性,这至少需要 30-40 个工作日的工作,所以我想看看是否可以可以在短期内加快速度。
不确定它是否有帮助,但构成此结果集的基础数据不会经常更改。经常发生变化的是 json blob 中更下方的数据。
SELECT
value::json ->> 'name' AS name,
value::json ->> 'mnemonic' AS mnemonic,
value::json ->> 'urlName' AS "urlName",
value::json ->> 'countryCode' AS "countryCode",
value::json #>>'{team}' AS team
FROM
data;
Run Code Online (Sandbox Code Playgroud)
Erw*_*ter 13
Like you mentioned yourself, the proper fix is to extract those attributes to separate columns, somewhat normalizing your design.
Sadly, no (as of Postgres 14).
It could work in theory. Since your values are big, an expression index with just some small attributes can be picked up by Postgres in an index-only scan, even when retrieving all rows (where it otherwise would ignore indexes).
然而,PostgreSQL 的规划器目前对于此类情况还不是很聪明。仅当查询所需的所有列均可从索引中获取时,它才认为查询可能通过仅索引扫描来执行。
因此,您必须将value
其自身包含在索引中,即使只是作为INCLUDE
列 - 完全破坏了整个想法。不去。
短期内你可能仍然可以做一些事情。两句关键的引言:
我想看看是否可以在短期内加快速度
json blob 有点大
将转换json
从查询中删除。每次铸造都会增加无意义的成本。
一个主要的成本因素是压缩。Postgres 必须“de-toast”整个大列,只是为了提取一些小属性。从Postgres 14开始,您可以切换压缩算法(如果您的版本启用了支持!)。默认值由 config 设置定义default_toast_compression
,即pglz
默认值。目前唯一可用的替代方案是lz4
. 您可以对每列进行设置。任何时候。
LZ4 ( lz4
) 的速度要快得多,但压缩率通常要低一些。速度大约是原来的两倍,但存储空间增加了大约 10%(具体取决于!)。如果性能不是问题,最好坚持使用默认 LZ 算法的更强压缩 ( pglz
)。未来可能会有更多的压缩算法可供选择。
实施:
ALTER TABLE data
ALTER COLUMN value SET COMPRESSION lz4;
Run Code Online (Sandbox Code Playgroud)
为列设置新值COMPRESSION
不会自动重新压缩。Postgres 会记住压缩方法,并且仅在强制解压缩时才重新压缩。您可能想要强制重新压缩现有值。您可以检查:
SELECT pg_column_compression(value) FROM data LIMIT 10;
Run Code Online (Sandbox Code Playgroud)
相关博文:
GENERATED
列当坚持破损的设计时,您可能只需添加一些(小!)生成的列来覆盖您的查询:
ALTER TABLE data
ADD COLUMN name text GENERATED ALWAYS AS (value::json ->> 'name') STORED
, ADD COLUMN mnemonic text GENERATED ALWAYS AS (value::json ->> 'mnemonic') STORED
...
Run Code Online (Sandbox Code Playgroud)
然后仅针对那些生成的列,根本不涉及大列。value
SELECT name, mnemonic, ... FROM data;
Run Code Online (Sandbox Code Playgroud)
这将绕过主要的性能问题。
看:
然而,您提到:
经常发生变化的是 json blob 中更下方的数据。
每次更改都会value
强制重新检查生成的列,从而增加写入成本。
归档时间: |
|
查看次数: |
19121 次 |
最近记录: |