VB_*_*VB_ 12 postgresql performance partitioning sharding performance-tuning
提高多达 1 亿行的表的读/写性能的常用方法是什么?
表有 column SEGMENT_ID INT NOT NULL,其中每个段有大约 100.000-1.000.000 行。写入 -SEGMENT_ID一次插入所有行,SEGMENT_ID之后不更新。读取 - 非常频繁,我需要良好的SELECT * FROM table WERE SEGMENT_ID = ?.
最明显的方法是SEGMENT_ID动态创建新表,但动态表意味着使用 ORM 甚至本机 SQL 查询框架进行黑客攻击。换句话说,你完成了有味道的代码。
您也可以使用分片,对吗?数据库是否在幕后创建新表?
我可以通过SEGMENT_ID. 但是,如果我一次插入所有与段相关的数据,我的插入是否会聚集在一起?
Postgres 还建议使用分区来处理非常大的表。
也许有某种神奇的索引可以帮助我避免动态创建新表或配置分片?
还有其他选择吗?
Eva*_*oll 11
BRIN索引蒂亚斯。
这是一个与您描述的完全相同的表,最坏的情况是 1 亿行,每行 100 万行 SEGMENT_ID
explain analyze
CREATE TABLE foo AS
SELECT (x::int%100)::int AS SEGMENT_ID
FROM generate_series(1,100e6) AS gs(x);
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
Function Scan on generate_series gs (cost=0.00..15.00 rows=1000 width=32) (actual time=21740.904..57589.405 rows=100000000 loops=1)
Planning time: 0.043 ms
Execution time: 96685.350 ms
(3 rows)
Run Code Online (Sandbox Code Playgroud)
这意味着我们在 1.5 分钟内创建了表。这里我们添加了一个索引。
CREATE INDEX ON foo
USING brin (SEGMENT_ID);
VACUUM ANALYZE foo;
Run Code Online (Sandbox Code Playgroud)
然后我们再添加一百万行。 SEGMENT_ID = 142
explain analyze
INSERT INTO foo(SEGMENT_ID)
SELECT 142
FROM generate_series(1,1e6) AS gs(x);
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
Insert on foo (cost=0.00..10.00 rows=1000 width=0) (actual time=1489.958..1489.958 rows=0 loops=1)
-> Function Scan on generate_series gs (cost=0.00..10.00 rows=1000 width=0) (actual time=174.690..286.331 rows=1000000 loops=1)
Planning time: 0.043 ms
Execution time: 1499.529 ms
(4 rows)
Run Code Online (Sandbox Code Playgroud)
添加一百万行需要 1.5 秒.. 现在我们选择,
explain analyze
SELECT *
FROM foo
WHERE SEGMENT_ID=142;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on foo (cost=52.00..56.01 rows=1 width=4) (actual time=4.401..140.874 rows=1000000 loops=1)
Recheck Cond: (segment_id = 142)
Rows Removed by Index Recheck: 24832
Heap Blocks: lossy=4535
-> Bitmap Index Scan on foo_segment_id_idx (cost=0.00..52.00 rows=1 width=0) (actual time=1.504..1.504 rows=46080 loops=1)
Index Cond: (segment_id = 142)
Planning time: 0.059 ms
Execution time: 176.902 ms
(8 rows)
Run Code Online (Sandbox Code Playgroud)
选择一百万行需要 176 毫秒。
那是在带有“Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz”和单个 SSD的 5 岁x230 上。您可以花几百美元购买一个并安装Xubuntu。也不完全是硬科学。我正在后台编译 Angular 应用程序。
提高1亿行表读写性能的常用方法有哪些?
不在手机上运行吗?我的意思是,说实话,在现代中端硬件上,数百百万行并不是特别大。这意味着 - 嗯,让我们看看。双路、16 核(我在这里只使用最低许可 Windows 标准,它与 AMD EPYC 的低端产品相匹配),可能是 128GB RAM 和全 SSD 设置,至少是大量 SSD 缓存的东西。
我的意思是,我的老虚拟机(sql server,使用 48GB 内存、6 个核心和大约 10 个专用 SSD)正在不到一秒的时间内处理 6400 万行插入/删除作业,没有任何特殊的情况。
最明显的方法是为 SEGMENT_ID 创建新表
这是专业数据库有一种叫做分区的东西。谷歌实际上告诉我 postgres 也有它 - https://www.postgresql.org/docs/current/static/ddl-partitioning.html - 你知道吗?从我看来,它比 SQL Server 稍微不优雅(似乎在每个分区上创建索引,而不是由数据库透明地处理)。
它不会使读取或写入速度更快,但删除整个分区可以显着加快速度。这里不需要动态,虽然你可以 - 要点是你永远不会使用子表,所以 ORM 和查询保持不变。
您也可以使用分片,对吗?
一旦你达到了数千亿行,你可能应该这样做。
它确实是分区,但前提是您的插入/删除方案使其高效。否则,答案确实是硬件,特别是因为 1 亿并不算多。分区几乎是唯一能与 ORM 很好地配合的解决方案。
任何真的,为什么是动态的?预生成。哦,还有……
我需要良好的性能 SELECT * FROM table WERE SEGMENT_ID = ?
分区在这里没有帮助。好的,这就是问题所在 - 分区可以帮助您搜索更少的数据,但是使用以segment_id 作为第一个字段的索引并按此字段进行过滤 - 效果完全相同。足够的RAM和FAST IO是快速读取数据的唯一解决方案。分区基本上是“快速删除一个分区”的事情 - 其他任何东西最多只能获得一点点好处。
| 归档时间: |
|
| 查看次数: |
33832 次 |
| 最近记录: |