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 не возвращал ничего, что действительно поймало меня. Итак, я достал кирку и фонарик.