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