PostgreSQL с использованием UUID vs Text в качестве первичного ключа

наша текущая база данных PostgreSQL использует GUID в качестве первичных ключей и сохраняет их в виде текстового поля.

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

Я думаю, что мы должны использовать UUID, поскольку они хранятся как двоичное представление GUID, где a Текст не является, и объем индексирования, который вы получаете в текстовом столбце, минимален.

Это был бы значительный проект, чтобы изменить их, и мне интересно, Стоит ли это того?

2 ответов


как упоминал @Kevin, единственный способ узнать наверняка с вашими точными данными - сравнить и сравнить оба метода, но из того, что вы описали, я не вижу, почему это будет отличаться от любого другого случая, когда строка была либо первичный ключ в таблице или части уникального индекса.

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

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

существуют другие стратегии смягчения для такого типа ситуации, такие как разбиение запроса на блоки, а затем UNIONing результаты (например, ручное моделирование того, что было бы сделано в куст или Импала на Hadoop сфере).

Re: ваша забота об индексации текста, в то время как я уверен, что есть некоторые случаи, когда набор данных создает распределение ключей такое, что оно выполняет ужасно, GUID, как md5sums, sha1 и т. д. должен индексироваться довольно хорошо в целом и не требует последовательного сканирования (если, как я уже упоминал выше, вы не запросите огромную полосу таблицы).

одним из больших факторов о том, как индекс будет работать, является количество уникальных значений. По этой причине логический индекс в таблице с большим количеством строк вряд ли поможет, поскольку он в основном будет иметь огромное количество строк коллизии для любого из значений (true, false и потенциально NULL) в индексе. С другой стороны, индекс GUID, вероятно, будет иметь огромное количество значений без коллизии (теоретически, поскольку они являются GUID).

Edit в ответ на комментарий от OP:

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

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

A UUID - 128-битный тип данных (так, 16 байт), тогда как текст 1 или 4 байта плюс фактическая длина строки. Для GUID это означало бы минимум 33 байт, но может значительно отличаться в зависимости от используемой кодировки.

Итак, имея это в виду, конечно, индексы текстовых UUID будут больше, так как значения больше, и сравнение двух строк против двух числовых значений теоретически менее эффективно, но это не то, что, вероятно, сделает огромную разницу в этом случае, по крайней мере, не обычные случаи.

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

в отношении ли Postgres знает, что строка является GUID, это определенно не по умолчанию. Насколько это касается, это просто уникальная строка. Но это должно быть хорошо для большинства случаев, например, совпадение строк и тому подобное. Если вы окажетесь требуется некоторое поведение, которое конкретно требует GUID (например, некоторые сравнения, основанные на неравенстве, где сравнение GUID может отличаться от чисто лексического), тогда вы всегда можете привести строку к UUID и Postgres будет обрабатывать значение как таковое во время этого запроса.

например, для текстового столбца foo, вы можете сделать foo::uuid чтобы бросить его в uuid.

есть также модуль для генерации uuids, uuid-ossp.


при работе с номерами UUID храните их как тип данных uuid. всегда. просто нет веских причин даже рассматривать text в качестве альтернативы. Ввод и вывод осуществляется через текстовое представление по умолчанию в любом случае. Гипс очень дешевый.

тип данных text требует больше места в ОЗУ и на диске, медленнее обрабатывать и более подвержен ошибкам. @khampson это обеспечивает большую часть обоснование. Странно, похоже, он пришел к другому выводу.

об этом уже спрашивали, отвечали и обсуждали раньше. Связанные вопросы по dba.SE с подробным объяснением:

bigint?

может быть, вам не нужны UUIDs (GUIDs) на все. Считать bigint. Он занимает всего 8 байт и быстрее во всех аспектах. Это диапазон часто недооценивается:

-9223372036854775808 to +9223372036854775807

это 9,2 миллиона миллионов миллионов положительных чисел. Десятки или сотни миллионов-это даже не близко.

IOW, если вы сжигаете 1 миллион идентификаторов в секунду (что безумно большое число), вы можете продолжать делать это для 292471 лет. А потом еще 292471 год для отрицательных чисел.
UUID действительно только для распределенных систем и других особых случаев.