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 uuidSET DATA TYPE uuid 的简写。 The manual:

SET DATA TYPE

这种形式改变了表格的列的类型。通过重新解析最初提供的表达式,涉及该列的索引和简单表约束将自动转换为使用新的列类型。 [...]

varchar_pattern_ops 是一个operator class,如果您有uuid 在任何索引中使用此运算符类,则会在您的错误消息中提及。通常用于实现更快的排序、模式匹配和范围条件。

要修复、删除冲突索引、更改数据类型,然后在没有特殊运算符类的情况下重新创建索引 - 如果您仍然需要它们。

但是,一些使用varchar_pattern_ops 索引的典型查询将停止使用数据类型uuid 而不是varchar。比如模式匹配:

PostgreSQL LIKE query performance variations

确保也修复任何此类查询。

@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 连接问题

Django/PostgreSQL 全文搜索 - 在 AWS RDS PostgreSQL 上使用 SearchVector 与 SearchVectorField 时的不同搜索结果

Django Postgresql ArrayField 聚合

完整性错误:更新或删除违反外键约束。 Django + PostgreSQL

Docker-compose实战——Django+PostgreSQL

django postgresql json 字段模式验证