Postgresql ArrayField против ForeignKey? какой из них является исполнителем? - PullRequest
0 голосов
/ 07 ноября 2019

Я хочу создать приложение для телефонной книги, в котором каждый контакт может иметь несколько номеров. Существует два варианта БД:

  1. использовать контакт внешний ключ в каждом число .
  2. хранить номера в ArrayField внутри каждого contact .

какое решение является более производительным и почему?

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 08 ноября 2019

Если вы строите индекс GIN для столбца массива, и Django будет писать запросы таким образом, чтобы они могли использовать этот индекс, то производительность чтения будет весьма схожей между ними.

Маловероятно, что разница в производительности станет движущей силой этого выбора. Например, вам нужно больше информации за номером телефона, чем просто номер, например, когда он был добавлен, когда он использовался в последний раз, будь то мобильный телефон или что-то еще, и т. Д.

Массивстолбец должен быть быстрее, потому что он должен обращаться только к одному индексу и таблице, а не к двум из каждого. Кроме того, он будет более компактным и, следовательно, более кэшируемым.

С другой стороны, статистические оценки для вашего столбца массива будут иметь проблему при оценке редких значений , что вы, скорее всего,иметь здесь, так как ни один номер телефона, скорее всего, не будет использоваться большим количеством людей. Эта мизерная оценка может иметь разрушительные результаты для производительности вашего запроса. Например, в небольшом тесте завышение количества строк во много тысяч раз привело к тому, что он запустил параллельный рабочий для однострочного запроса, что привело к тому, что он был примерно в 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. (Для удобства я использовал целые, а не текстовое поле, которое вы, вероятно, использовали бы для телефонных номеров, но это не меняет ничего фундаментального).

Если это действительно важно для вас, то выдолжен сделать тест и посмотреть, используя ваши собственные данные и вашу собственную архитектуру. Это будет зависеть от того, что помещается и не помещается в памяти, какие типы запросов вы выполняете (вы когда-нибудь просматривали числа в большом количестве? Присоедините их к другим таблицам, помимо сразу обсуждаемого внешнего ключа?), И, возможно, как ваш драйвер /столбцы / параметры библиотеки с типами массивов.

0 голосов
/ 07 ноября 2019

Очевидно, вы должны использовать ForeignKey.

Если я четко понимаю вашу задачу, ваша производительность снизится, когда вы попытаетесь найти контакт по номеру телефона.

Вы должны использовать contact_id в качестве индекса БД в числовой таблице, и ваша производительность будет лучше, чем при использовании ArrayField

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...