有效处理10-1亿行无关数据行表

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 应用程序。


Tom*_*Tom 4

提高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是快速读取数据的唯一解决方案。分区基本上是“快速删除一个分区”的事情 - 其他任何东西最多只能获得一点点好处。

  • Windows 是图形化的。管理工具是图形化的。本质上,您是在 SQL Server 的基础上指定一台 PostgreSQL 机器。我认为这不公平。SQL Server 的设计并不完善。你的“双路16核”从何而来?据我所知,这甚至不是 SQL Server 的技术要求。这是许可的业务要求。从本质上讲,微软只是想以此来让你失望。他们可以将其设置为 150 个核心,但这仍然是任意定价。 (2认同)