Django/PostgreSQL varchar для UUID

Я пытаюсь обновить проект с Django 1.7 до 1.9. К сожалению он использовал django-расширения UUIDfield который использовал varchar внутренне. Я пытаюсь изменить эти поля на uuid введите в базу данных.

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

alter table tablename alter column guid type uuid using guid::uuid;

Я получаю эту ошибку:

ОШИБКА: класс операторов "varchar_pattern_ops" не принимает тип данных uuid

Я действительно не очень хорошо знаком с PostgreSQL и немного в себе. Могу ли я создать CAST или что-то, чтобы это исправить? Я не могу понять, как я буду.

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

3 ответа

Решение

type uuid в вашем заявлении DDL является сокращением для SET DATA TYPE uuid, Руководство:

SET DATA TYPE

Эта форма изменяет тип столбца таблицы. Индексы и простые ограничения таблиц, включающие столбец, будут автоматически преобразованы для использования нового типа столбца путем повторного анализа первоначально предоставленного выражения. [...]

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

Чтобы исправить, удалите конфликтующие индексы, измените тип данных, а затем заново создайте индексы без специального класса операторов - если они вам все еще нужны.

Тем не менее, некоторые типичные запросы, которые будут использовать varchar_pattern_ops Индекс перестанет работать с типом данных uuid вместо varchar, Как сопоставление с шаблоном:

Обязательно исправьте и такие запросы.

@ fl0cke указал на связанный ответ:

Я предлагаю немного другой маршрут. Дешевле отбрасывать индекс, изменять тип данных, а затем создавать новый индекс - если он все еще полезен.

DROP INDEX tbl_guid_varchar_pattern_ops_idx;

ALTER TABLE tbl ALTER COLUMN guid TYPE uuid USING guid::uuid;

CREATE INDEX tbl_guid_idx ON tbl (guid);

Как найти оскорбительный индекс?

Мне нужно выяснить, как изучить существующие индексы.

В современных версиях Postgres вы получаете существующие индексы для таблицы с \d tbl в пскл.

Чтобы получить все завершено CREATE INDEX утверждения для данной таблицы:

SELECT pg_get_indexdef(indexrelid) || ';' AS idx
FROM   pg_index
WHERE  indrelid = 'public.tbl'::regclass;  -- optionally schema-qualified

Чтобы получить только те, которые используют varchar_pattern_ops:

SELECT pg_get_indexdef(i.indexrelid) || ';' AS idx
FROM   pg_index i
JOIN   pg_opclass o ON o.oid = ANY (i.indclass)
WHERE  i.indrelid = 'public.big'::regclass
AND    o.opcname = 'varchar_pattern_ops';

Подробности:

Начиная с Postgresql 9.5 может быть доступна другая опция. Теперь существует класс операторов uuid https://www.postgresql.org/docs/9.5/static/brin-builtin-opclasses.html. Конечно, у меня все еще есть 9.4:-(. Это сообщение в блоге помогает объяснить проблему и имеет исправление, которое, я полагаю, все еще работает, но оно также до 9.5: https://coderwall.com/p/1b5eyq/index-for-uuid-array-data-type

Обратите внимание, что блог специально ссылается на использование uuid в массиве, в то время как новый класс операторов специально ссылается на BRIN. Пусть покупатель будет бдителен.

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

Это приложение использует Django 1.11, Py3 и переносит из раннего локального разработчика на SQLite (только для подтверждения концепции). При миграции в PG у меня была такая же ошибка:

ОШИБКА: класс операторов "varchar_pattern_ops" не принимает тип данных uuid

Мне удалось это исправить 2 способами. На ранней стадии приложения я смог стереть и начать с нуля. Я знаю, что это редко вариант, но мои действия предоставляют полезные подсказки для исправления этого в сценарии миграции или обновления. У меня есть хорошие отбросы SQL/PG, пришедшие со времени, когда использование ORM не было обычным делом. Этот вопрос стал для меня настоящей царапиной.

Эта проблема

В моем 5-летнем мозгу проблема возникла из-за изменения типов столбцов, перехода от строки к UUID "нативному". Посредством миграций в моем приложении, кажется, создается столбец, который не является собственным UUID. С введением модели Джанго UUIDField требование не удалось удовлетворить и выбросило вышеупомянутую ошибку. Проблема в том, чтобы делать что-то глупое, переходя от типа str к int в БД со значениями не-int.

Исправить информацию

Мне удалось это исправить 2 способами.

Сначала было через сквош Джанго. Я уже сталкивался с подобной ошибкой, связанной с использованием UUID в моем приложении, поэтому я знал об этой схеме ошибок. При сжатии миграции вы пропускаете более раннее создание столбца, не являющегося UUIDField, и выполняете только правильное объявление столбца. Когда я перезапустил (свежий) migrate все прошло просто отлично.

Второй способ вряд ли является вариантом, но я убил все миграции и начал с текущего состояния. Тот же эффект, что и предыдущий.

Так..

С учетом всего вышесказанного, я смог перепроектировать проблему так, чтобы это работало в моей голове. "Исправление" заключалось в том, чтобы никогда не создавать столбец, отличный от UUIDField. Моя проблема была связана с обменом SQLite на PG (AFIK).

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

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

Другие вопросы по тегам