val*_*mit 4 postgresql cache explain timescaledb postgresql-performance
我正在尝试调查为什么此查询的性能如此不确定。它可能需要 1 秒到 60 秒及以上的任何时间。查询的本质是选择一个“时间窗口”,并从该时间窗口内获取所有行。
这是有问题的查询,在大约 10 亿行的表上运行:
SELECT CAST(extract(EPOCH from ts)*1000000 as bigint) as ts
, ticks
, quantity
, side
FROM order_book
WHERE ts >= TO_TIMESTAMP(1618882633073383/1000000.0)
AND ts < TO_TIMESTAMP(1618969033073383/1000000.0)
AND zx_prod_id = 0
ORDER BY ts ASC, del desc;
Run Code Online (Sandbox Code Playgroud)
这就是表的创建方式
CREATE TABLE public.order_book
(
ts timestamp with time zone NOT NULL,
zx_prod_id smallint NOT NULL,
ticks integer NOT NULL,
quantity integer NOT NULL,
side boolean NOT NULL,
del boolean NOT NULL
)
Run Code Online (Sandbox Code Playgroud)
TO_TIMESTAMP
当我走整张桌子时,其中的值将继续向前滑动。以下是EXPLAIN ANALYZE
两个不同时间窗口上相同查询的输出:
性能缓慢
Gather Merge (cost=105996.20..177498.48 rows=586308 width=18) (actual time=45196.559..45280.769 rows=539265 loops=1)
Workers Planned: 6
Workers Launched: 6
Buffers: shared hit=116386 read=42298
-> Sort (cost=104996.11..105240.40 rows=97718 width=18) (actual time=45169.717..45176.775 rows=77038 loops=7)
Sort Key: (((date_part('epoch'::text, _hyper_16_214_chunk.ts) * '1000000'::double precision))::bigint), _hyper_16_214_chunk.del DESC
Sort Method: quicksort Memory: 9327kB
Worker 0: Sort Method: quicksort Memory: 8967kB
Worker 1: Sort Method: quicksort Memory: 9121kB
Worker 2: Sort Method: quicksort Memory: 9098kB
Worker 3: Sort Method: quicksort Memory: 9075kB
Worker 4: Sort Method: quicksort Memory: 9019kB
Worker 5: Sort Method: quicksort Memory: 9031kB
Buffers: shared hit=116386 read=42298
-> Result (cost=0.57..96897.07 rows=97718 width=18) (actual time=7.475..45131.932 rows=77038 loops=7)
Buffers: shared hit=116296 read=42298
-> Parallel Index Scan using _hyper_16_214_chunk_order_book_ts_idx on _hyper_16_214_chunk (cost=0.57..95187.01 rows=97718 width=18) (actual time=7.455..45101.670 rows=77038 loops=7)
Index Cond: ((ts >= '2021-04-22 01:34:31.357179+00'::timestamp with time zone) AND (ts < '2021-04-22 02:34:31.357179+00'::timestamp with time zone))
Filter: (zx_prod_id = 0)
Rows Removed by Filter: 465513
Buffers: shared hit=116296 read=42298
Planning Time: 1.107 ms
JIT:
Functions: 49
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 9.273 ms, Inlining 0.000 ms, Optimization 2.008 ms, Emission 36.235 ms, Total 47.517 ms
Execution Time: 45335.178 ms
Run Code Online (Sandbox Code Playgroud)
快速性能
Gather Merge (cost=105095.94..170457.62 rows=535956 width=18) (actual time=172.723..240.628 rows=546367 loops=1)
Workers Planned: 6
Workers Launched: 6
Buffers: shared hit=158212
-> Sort (cost=104095.84..104319.16 rows=89326 width=18) (actual time=146.702..152.849 rows=78052 loops=7)
Sort Key: (((date_part('epoch'::text, _hyper_16_214_chunk.ts) * '1000000'::double precision))::bigint), _hyper_16_214_chunk.del DESC
Sort Method: quicksort Memory: 11366kB
Worker 0: Sort Method: quicksort Memory: 8664kB
Worker 1: Sort Method: quicksort Memory: 8986kB
Worker 2: Sort Method: quicksort Memory: 9116kB
Worker 3: Sort Method: quicksort Memory: 8858kB
Worker 4: Sort Method: quicksort Memory: 9057kB
Worker 5: Sort Method: quicksort Memory: 6611kB
Buffers: shared hit=158212
-> Result (cost=0.57..96750.21 rows=89326 width=18) (actual time=6.145..127.591 rows=78052 loops=7)
Buffers: shared hit=158122
-> Parallel Index Scan using _hyper_16_214_chunk_order_book_ts_idx on _hyper_16_214_chunk (cost=0.57..95187.01 rows=89326 width=18) (actual time=6.124..114.023 rows=78052 loops=7)
Index Cond: ((ts >= '2021-04-22 01:34:31.357179+00'::timestamp with time zone) AND (ts < '2021-04-22 02:34:31.357179+00'::timestamp with time zone))
Filter: (zx_prod_id = 4)
Rows Removed by Filter: 464498
Buffers: shared hit=158122
Planning Time: 0.419 ms
JIT:
Functions: 49
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 10.405 ms, Inlining 0.000 ms, Optimization 2.185 ms, Emission 39.188 ms, Total 51.778 ms
Execution Time: 274.413 ms
Run Code Online (Sandbox Code Playgroud)
我将此输出解释为大部分归咎于并行索引扫描。
起初,我试图提高work_mem
到 1 GB 和shared_buffers
24 GB,认为它可能无法在 RAM 中容纳它需要的所有东西,但这似乎没有帮助。
接下来,我尝试在 上创建索引(zx_prod_id, ts)
,认为并行索引扫描的过滤器可能需要一段时间,但这似乎也没有做任何事情。
我不是数据库专家,所以我已经用尽了我的知识极限。
两个查询计划之间最重要的区别是read=xyz
在慢速版本的多个地方添加了位。
减缓:
Buffers: shared hit=116296 read=42298
Run Code Online (Sandbox Code Playgroud)
快速地:
Buffers: shared hit=158122
Run Code Online (Sandbox Code Playgroud)
这告诉您 Postgres 遇到了尚未缓存的数据(或索引)页面。重复慢速查询(可能read=xyz
不止一次,直到添加的内容消失),然后您将在同等缓存的数据页上看到类似的性能。
有关的:
值得注意的是,增加work_mem
实际上会损害您的情况,因为work_mem
缓存内存(操作系统缓存和 Postres 自己的共享内存缓冲区)是可用 RAM 的竞争对手。设置得work_mem
更高会导致数据更快地从(然后更小)缓存中被逐出,因此您的“慢查询”变得更有可能发生。不要忘记 Postgres 可以使用work_mem
. 手册:
请注意,对于复杂查询,可能会并行运行多个排序或散列操作;在开始将数据写入临时文件之前,通常允许每个操作使用与此值指定的内存一样多的内存。此外,多个正在运行的会话可能会同时执行此类操作。因此,使用的总内存可能是
work_mem
;
您的查询使用 6 个并行工作器,这已经是 6 倍work_mem
- 可能是最坏的情况;并非每个工人都会使用其最大津贴。
如果不足,work_mem
您会disk
在EXPLAIN
输出的各种上下文中看到提到的内容。那是额外的时候work_mem
。
增加shared_buffers
可能更有意义。不过,也不要设置得太高。手册:
如果您有一个具有 1GB 或更多 RAM 的专用数据库服务器,shared_buffers 的合理起始值是系统内存的 25%。有一些工作负载甚至更大的设置
shared_buffers
也有效,但由于 PostgreSQL 也依赖于操作系统缓存,因此分配超过 40% 的 RAM 不太可能比较shared_buffers
小的数量更好。
如果您有足够的 RAM 存储所有内容(很难想象“具有 10 亿行的表”),那么所缺少的只是有问题的数据页尚未缓存。您可能对pg_prewarm
. 看:
旁白:第二个查询计划显示Filter: (zx_prod_id = 4)
,它与显示的查询不匹配,但我认为这对问题无关紧要。
你已经尝试了一个索引,(zx_prod_id, ts)
但它......
似乎什么也没做。
不过,该索引通常对查询来说看起来不错。
多列索引比以下索引大 50% 左右(ts)
:4 + 8 + 16 = 28 个字节 vs. 4 + 8 + 8 = 每个索引元组 20 个字节,并且可能来自“索引重复数据删除”的压缩更少。而且由于 RAM 似乎是一种有争议的资源,这是一个缺点。看:
我看到rows=539265
vs. Rows Removed by Filter: 465513
. 所以查询读取它需要的行的两倍。根据数据分布,该指数可能是也可能不是改进。如果您的表物理地聚集在该索引上,那肯定是这样。然后大多数数据页包含具有相同zx_prod_id
值的行,这使得该索引更加有效。再看:
您的查询似乎总是过滤单个值zx_prod_id
。如果这集中在几个值上,或者如果开始时只有几个不同的值,那么几个部分索引可能是有意义的。就像,如果只有zx_prod_id IN (1,4)
目标:
CREATE INDEX order_book_ts_zx1_idx ON order_book (ts) WHERE zx_prod_id = 1;
CREATE INDEX order_book_ts_zx4_idx ON order_book (ts) WHERE zx_prod_id = 4;
Run Code Online (Sandbox Code Playgroud)
然后查询可以使用(远)更小的索引,并且不必过滤一半的行。
ts
显然是 type timestamptz
。您仍然将时间戳作为bigint
代表微秒的数字处理。这种拆分方法有缺点和缺陷。通常最好使用整个食物链的时间戳。CAST(extract(EPOCH from ts)*1000000 as bigint)
为每一行执行不是免费的。加起来有五十万行。
归档时间: |
|
查看次数: |
91 次 |
最近记录: |