Django/PostgreSQL varchar 到 UUID
Posted
技术标签:
【中文标题】Django/PostgreSQL varchar 到 UUID【英文标题】:Django/PostgreSQL varchar to UUID 【发布时间】:2016-05-10 10:51:20 【问题描述】:我正在尝试将项目从 Django 1.7 更新到 1.9。不幸的是,它使用了 django-extensions UUIDfield
,它在内部使用了 varchar
。我正在尝试将这些字段更改为数据库中的 uuid
类型。
我已经创建了一个自定义迁移,告诉 Django 迁移将使用它自己的 SQL 来完成它。当我这样做时,我的问题就来了(该列名为guid
):
alter table tablename alter column guid type uuid using guid::uuid;
我收到此错误:
错误:运算符类“varchar_pattern_ops”不接受数据类型 uuid
我对 PostgreSQL 真的不是很熟悉,而且有点不知所措。我可以创建一个 CAST 或其他东西来解决这个问题吗?我不知道该怎么做。
我正在尝试使用 script from here,它应该负责处理索引依赖关系,但我真的很头疼。
【问题讨论】:
这能回答你的问题吗? ***.com/questions/20284557/… @fl0cke 它为我指明了正确的方向,但要做到这一点,我需要弄清楚如何检查现有索引,以便之后重新创建它们。 在 psql 终端中尝试\d tablename
。
您忘记提及您的 Postgres 版本。
【参考方案1】:
DDL 语句中的type uuid
是SET DATA TYPE uuid
的简写。 The manual:
SET DATA TYPE
这种形式改变了表格的列的类型。通过重新解析最初提供的表达式,涉及该列的索引和简单表约束将自动转换为使用新的列类型。 [...]
varchar_pattern_ops
是一个operator class,如果您有uuid
在任何索引中使用此运算符类,则会在您的错误消息中提及。通常用于实现更快的排序、模式匹配和范围条件。
要修复、删除冲突索引、更改数据类型,然后在没有特殊运算符类的情况下重新创建索引 - 如果您仍然需要它们。
但是,一些使用varchar_pattern_ops
索引的典型查询将停止使用数据类型uuid
而不是varchar
。比如模式匹配:
确保也修复任何此类查询。
@fl0cke pointed out相关回答:
Postgresql operator class "varchar_pattern_ops" does not accept data type integer我建议一条稍微不同的路线。删除索引、更改数据类型并然后创建一个新索引会更便宜——如果它仍然有用的话。
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 中,您可以在 psql 中使用 \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';
详情:
Copy indexes from one table to another How can I drop all indexes of a table in Postgres?【讨论】:
很好,全面的答案。当我回到这里时,我自己解决了大部分问题。我最终手动删除了与相关表冲突的索引和约束,保存了我所做的,然后使用 pgdump 轻松转储命令以重新创建索引和约束。我花了几个小时,现在我知道我在做什么,我可能可以自动化它。【参考方案2】:我刚遇到这个问题,想添加信息。在解决这个问题时,我通过迁移来解决这个问题。任何可以添加到这里的人,请随意,包括更正。
这个应用程序使用 Django 1.11、Py3,并且正在从 SQLite 上的早期本地开发人员迁移出去(只是为了证明一些概念)。迁移到 PG 时,我遇到了同样的错误:
错误:操作符类“varchar_pattern_ops”不接受数据类型 uuid
我能够通过两种方式修复它。在应用程序的早期阶段,我能够擦除并从头开始。我知道这很少是一种选择,但我的行动为在迁移或升级方案中解决此问题提供了有用的线索。在 ORM 使用不常见的时候,我有很好的 SQL/PG 印章。这个问题真是让我头疼。
问题
在我 5 岁的大脑中,问题来自于更改列类型,从字符串到 UUID “本机”。通过我的应用程序中的迁移,似乎创建了一个不是 UUID 本机的列。随着Django的模型UUIDField
的引入,需求无法满足并抛出上述错误。这个问题类似于在数据库中使用非 int 值从 str 类型转换为 int 类型。
修复信息
我能够解决这两种方法。
首先是通过 Django 的 squash 迁移。我已经在我的应用程序中遇到了与 UUID 使用相关的类似错误,所以我知道这种错误模式。通过压缩迁移,您可以跳过早期的非 UUIDField 列创建,只执行正确的列声明。当我重新运行(新鲜)migrate
时,一切都很好。
第二种方式几乎没有变化,但我杀死了所有迁移并从当前状态开始。效果和之前一样。
所以..
综上所述,对我而言,我能够以一种在我脑海中起作用的方式对问题进行逆向工程。 “修复”是除了 UUIDField 友好的方式之外,永远不要创建列。我的问题与 SQLite 到 PG 交换 (AFIK) 有关。
如果我正在进行升级,我认为杀死索引并重新创建它们的解决方案是要走的路。
再次,只是试图在此错误上提供一些信息,googleweb 没有返回任何真正吸引我的信息。所以我拿出了镐和手电筒。
【讨论】:
【参考方案3】:从 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/PostgreSQL varchar 到 UUID的主要内容,如果未能解决你的问题,请参考以下文章
Django/PostgreSQL 全文搜索 - 在 AWS RDS PostgreSQL 上使用 SearchVector 与 SearchVectorField 时的不同搜索结果
Django Postgresql ArrayField 聚合
完整性错误:更新或删除违反外键约束。 Django + PostgreSQL