【问题标题】:Postgresql ArrayField vs ForeignKey? which one is performant?Postgresql ArrayField vs ForeignKey?哪一个是高性能的?
【发布时间】:2020-03-04 07:31:55
【问题描述】:

我想设计一个电话簿应用程序,每个联系人可以有多个号码。有两种数据库设计:

  1. 在每个号码中使用contact外键。
  2. 将号码存储在每个联系人内的ArrayField

哪种解决方案在生产中性能更高,为什么?

提前致谢。

【问题讨论】:

    标签: django database postgresql optimization


    【解决方案1】:

    如果您在数组列上构建 GIN 索引,并且 Django 将编写查询以使用该索引,那么两者的读取性能将非常相似。

    性能差异不太可能成为此选择背后的驱动因素。例如,除了电话号码之外,您是否需要电话号码背后的更多信息,例如添加的时间,上次使用的时间,是手机还是其他东西等。

    数组列应该更快,因为它只需要查询一个索引和表,而不是每个两个。此外,它会更紧凑,因此更易于缓存。

    另一方面,当estimating rare values 时,您的数组列的统计估计会出现问题,您可能会在这里遇到问题,因为没有电话号码可能会被很多人共享。这种错误估计可能会对您的查询性能产生毁灭性的影响。例如在一个小测试中,高估了数千倍的行数导致它为单行查询启动并行工作者,导致它比关闭并行化时慢约 20 倍,比使用时慢 10 倍不受估计问题影响的外键表示。

    例如:

    create table contact as select md5(floor(random()*50000000)::text) as name, array_agg(floor(random()*100000000)::int) phones from generate_series(1,100000000) f(x) group by name;
    vacuum analyze contact;
    create index on contact using gin (phones );
    explain analyze select * from contact where phones @> ARRAY[123456];
                                                                     QUERY PLAN                                                                 
    --------------------------------------------------------------------------------------------------------------------------------------------
     Gather  (cost=3023.30..605045.19 rows=216167 width=63) (actual time=0.668..8.071 rows=2 loops=1)
       Workers Planned: 2
       Workers Launched: 2
       ->  Parallel Bitmap Heap Scan on contact  (cost=2023.30..582428.49 rows=90070 width=63) (actual time=0.106..0.110 rows=1 loops=3)
             Recheck Cond: (phones @> '{123456}'::integer[])
             Heap Blocks: exact=2
             ->  Bitmap Index Scan on contact_phones_idx  (cost=0.00..1969.25 rows=216167 width=0) (actual time=0.252..0.252 rows=2 loops=1)
                   Index Cond: (phones @> '{123456}'::integer[])
     Planning Time: 0.820 ms
     Execution Time: 8.137 ms
    

    您可以看到它估计了 216167 行,但实际上只有 2 行。(为方便起见,我使用整数,而不是您可能用于电话号码的文本字段,但这不会改变任何基本的东西)。

    如果这对您来说真的很重要,那么您应该使用自己的数据和自己的架构进行测试并查看。这将取决于内存中的内容和不适合的内容,您正在执行的查询类型(您是否曾经批量查找数字?除了立即讨论的外键之外,将它们加入其他表?),也许您的驱动程序/库处理具有数组类型的列/参数。

    【讨论】:

    • 对不起,我没有清楚地了解第二部分。你能举个例子告诉我吗?
    猜你喜欢
    • 2021-03-13
    • 2022-10-17
    • 1970-01-01
    • 1970-01-01
    • 2018-10-20
    • 2011-10-06
    • 2015-12-21
    • 1970-01-01
    • 2011-07-03
    相关资源
    最近更新 更多