0
点赞
收藏
分享

微信扫一扫

理解effective_cache_size


引言

关于PostgreSQL的性能以及effective_cache_size参数已经写过很多了,然而,却很少有人知道这个著名的参数的意思,让我分享更多的见解。

优化器做了些什么

SQL背后的思想实际上很简单:用户发送一个查询,优化器需要找到执行该查询的最佳策略。优化器的输出就是人们所说的执行计划。现在的问题是:是什么让一个执行计划比其他计划更好?是什么让一个策略比其他策略更强大?在PostgreSQL中,一切都可以归结为“成本”这个概念。规划器会为每一步操作分配“成本”,最终会选择一个最便宜的计划并执行。因此,优化器处理成本的方式很神奇,而这也正是effective_cache_size的意义所在。

理解effective_cache_size

为了获得良好的性能,确定能否使用索引十分重要。一个经常被问到的问题是:为什么不总是使用索引?遍历和使用索引可能并不“便宜”,并且使用索引也并不意味着不需要再回表。因此,优化器必须决定是否使用索引。

估算成本的方式取决于多种因素:所需的 I / O次数,调用的运算符数量,处理的元组数量,选择性等等。但是,I / O成本是什么?显然,如果数据已经在高速缓存中或必须从磁盘读取数据,这二者之间有很大的差距。这使我们想到了effective_cache_size背后的想法,effective_cache_size可以告诉优化器,系统中预计有多少缓存。重要的是,“缓存”不仅仅是已知的内存量(这一部分非常清楚)。系统还必须考虑文件系统缓存,CPU缓存等大小。effective_cache_size是所有这些缓存的总和。您将在本文中学到的是优化器如何使用此类信息。

实际中的effective_cache_size

在我们迷失在理论解释之前,先研究一个实际的例子是有意义的。出于本博客的目的,我创建了两个表:

test=# CREATE TABLE t_random AS SELECT id, random() AS r 
FROM generate_series(1, 1000000) AS id ORDER BY random();
SELECT 1000000
test=# CREATE TABLE t_ordered AS SELECT id, random() AS r
FROM generate_series(1, 1000000) AS id;
SELECT 1000000
test=# CREATE INDEX idx_random ON t_random (id);
CREATE INDEX
test=# CREATE INDEX idx_ordered ON t_ordered (id);
CREATE INDEX
test=# VACUUM ANALYZE ;
VACUUM

请注意,两个表的数据相同。一张表数据是有序的,另一张没有。让我们将effective_cache_size设置为一个非常小的值。优化器会假设系统中真的没有太多内存:

test=# SET effective_cache_size TO '1 MB';
SET
test=# SET enable_bitmapscan TO off;
SET
test=# explain SELECT * FROM t_random WHERE id < 1000;
QUERY PLAN
---------------------------------------------------------------------------------
Index Scan using idx_random on t_random (cost=0.42..3611.96 rows=909 width=12)
Index Cond: (id < 1000)
(2 rows)

通常PostgreSQL会进行bitmap index scap,但我们想看看索引扫描会发生什么。因此我们关闭位图扫描(这会使它们对优化器来说异常昂贵)。让我们把这个计划和我们刚才看过的计划比较一下:

test=# SET effective_cache_size TO '1000 GB';
SET
test=# explain SELECT * FROM t_random WHERE id < 1000;
QUERY PLAN
--------------------------------------------------------------------------------
Index Scan using idx_random on t_random (cost=0.42..3383.99 rows=909 width=12)
Index Cond: (id < 1000)
(2 rows)

正如你所看到的,index scan的成本下降了。这有什么关系?我们必须把成本看作是相对的。绝对值并不重要,重要的是一个计划和其他计划相比有多昂贵。如果顺序扫描的代价保持不变,而索引扫描的代价相对于顺序扫描来说下降了,那么PostgreSQL将较平时更倾向于使用索引。这也正是effective_cache_size的核心所在:如果有大量的内存,就更有可能进行索引扫描。

限制和特殊情况

当人们谈论postgresql.conf和effective_cache_size时,他们往往没有意识到这个参数并不总是能产生奇迹。下面的场景展示了没有影响的情况:

test=# SET effective_cache_size TO '1 MB';
SET
test=# explain SELECT * FROM t_ordered WHERE id < 1000;
QUERY PLAN
----------------------------------------------------------------------------------
Index Scan using idx_ordered on t_ordered (cost=0.42..39.17 rows=1014 width=12)
Index Cond: (id < 1000)
(2 rows)

test=# SET effective_cache_size TO '1000 GB';
SET
test=# explain SELECT * FROM t_ordered WHERE id < 1000;
QUERY PLAN
----------------------------------------------------------------------------------
Index Scan using idx_ordered on t_ordered (cost=0.42..39.17 rows=1014 width=12)
Index Cond: (id < 1000)
(2 rows)

优化器所使用的表统计信息包含“物理相关性”。如果相关性为1(即所有的数据在磁盘上是有序的),这样的话effective_cache_size不会改变任何东西。果只有一列(如下一个示例所示),也同样适用:

test=# ALTER TABLE t_random DROP COLUMN r;
ALTER TABLE
test=# SET effective_cache_size TO '1 MB';
SET
test=# explain SELECT * FROM t_ordered WHERE id < 1000;
QUERY PLAN
----------------------------------------------------------------------------------
Index Scan using idx_ordered on t_ordered (cost=0.42..39.17 rows=1014 width=12)
Index Cond: (id < 1000)
(2 rows)

test=# SET effective_cache_size TO '1000 GB';
SET
test=# explain SELECT * FROM t_ordered WHERE id < 1000;
QUERY PLAN
----------------------------------------------------------------------------------
Index Scan using idx_ordered on t_ordered (cost=0.42..39.17 rows=1014 width=12)
Index Cond: (id < 1000)
(2 rows)

这对大多数用户来说都是一个惊喜,因此我认为值得一提。

调整effective_cache_size

我发现使用一个简单的公式来粗略估计一个好的设置是很有用的:effective_cache_size= RAM * 0.7。有些人也使用了RAM * 0.8。当然,这只针对我们讨论的是专用数据库服务器时,你可以自由实验。

译者著:pg_stats视图的correlation列对“相关性”有说明:Statistical correlation between physical row ordering and logical ordering of the column values. This ranges from -1 to +1. When the value is near -1 or +1, an index scan on the column will be estimated to be cheaper than when it is near zero, due to reduction of random access to the disk. (This column is null if the column data type does not have a < operator.)

原文:https://www.cybertec-postgresql.com/en/effective_cache_size-a-practical-example/


举报

相关推荐

0 条评论