Django/PostgreSQL varchar转UUID

6
我正在将一个Django 1.7的项目升级到1.9。不幸的是它使用了django-extensions的UUIDfield,该字段在内部使用varchar。我正在尝试将这些字段更改为数据库中的uuid类型。
我已经创建了自定义迁移,并告诉Django迁移将使用自己的SQL来完成。我的问题出现在我执行以下操作时(列名为guid):
alter table tablename alter column guid type uuid using guid::uuid;

我遇到了这个错误:
ERROR: operator class "varchar_pattern_ops" 不接受 uuid 数据类型。
我对 PostgreSQL 不是很熟悉,感觉有点不知所措。我能否创建一个 CAST 或其他什么来解决这个问题?我无法想出如何解决。
我正在尝试使用此处的脚本,它应该可以处理索引依赖关系,但我真的是不知所措。

这个回答解决了你的问题吗? https://dev59.com/KmIj5IYBdhLWcg3waEj9 - fl0cke
@fl0cke 指引我朝着正确的方向,但为了做到这一点,我需要弄清楚如何检查现有的索引,以便在之后重新创建它们。 - std''OrgnlDave
在 psql 终端中尝试使用 \d tablename - fl0cke
你忘了提到你的Postgres版本。 - Erwin Brandstetter
3个回答

3
在DDL语句中,type uuid表示 SET DATA TYPE uuid 的简写。手册链接:The manual:

SET DATA TYPE

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

varchar_pattern_ops是一个操作符类,如果有任何索引使用此操作符类与uuid一起使用,则会在错误信息中提到此类。通常用于启用更快的排序、模式匹配和范围查询。
要解决问题,请删除冲突的索引,更改数据类型,然后重新创建不带特殊操作符类的索引——如果需要使用它们。
但是,在使用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中,您可以使用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';

详情:


好的,全面的回答。我在回到这里之前自己解决了大部分问题。最终,我手动删除了与相关表格冲突的索引和约束,保存了所做的更改,然后使用pgdump获取了一个简单的命令转储来重新创建索引和约束。这花费了我几个小时,现在我知道该怎么做,可能可以自动化。 - std''OrgnlDave

0

在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。买方自负。


-1

我刚遇到这个问题,想要添加一些信息。在解决这个问题时,我通过迁移来理解了它。任何能够补充的人,请随意添加,包括更正。

这个应用程序正在使用 Django 1.11、Py3,并且正在从早期的本地 SQLite 开发中迁移到 PG(只是为了证明一些概念)。当迁移到 PG 时,我遇到了同样的错误:

ERROR: operator class "varchar_pattern_ops" does not accept data type uuid

我有两种方法可以解决它。在我的应用程序早期阶段,我能够清除并从头开始。我知道这很少是一个选项,但我的行动为在迁移或升级方案中修复此问题提供了有用的线索。我在 ORM 不常用的时候就已经掌握了良好的 SQL/PG 技巧。这个问题对我来说真是一个难题。

问题

在我五岁的大脑中,问题是通过更改列类型而来的,从字符串到UUID "本地"。通过应用程序中的迁移似乎创建了一个不是UUID本地的列。随着Django模型UUIDField的引入,需求无法满足并抛出了上述错误。这个问题类似于在具有非整数值的情况下从str到int类型在数据库中做一些愚蠢的事情。
修复信息
我有两种方法来解决这个问题。
第一种方法是通过Django的压缩迁移。我已经遇到了与我的应用程序中UUID使用相关的类似错误,所以我知道这种错误的模式。通过压缩迁移,您可以跳过早期的非UUIDField列创建,并仅执行正确的列声明。当我重新运行(新鲜)迁移时,一切都很顺利。
第二种方法几乎没有变化,但我杀死了所有迁移并从当前状态开始。与之前的效果相同。
所以...

说了这么多,对我来说,我能够以一种符合我的思维方式的方式来逆向工程解决问题。 "修复" 的方法是永远不要将列设置为除了 UUIDField 友好方式之外的方式。我的问题与 SQLite 到 PG 交换有关(据我所知)。

如果我进行升级,我认为删除索引并重新创建它们是正确的方法。

再次强调,只是尝试提供一些关于这个错误的信息,但谷歌并没有返回任何真正吸引我的内容。所以我拿出了镐和手电筒。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接