WHERE name = 'cat' 失败,而 `WHERE name LIKE '%cat` 在 PostGres 上工作
WHERE name = 'cat' fails while `WHERE name LIKE '%cat` works on PostGres
我在 Postgres 上有一个非常简单的查询,它以 WHERE =
失败,但适用于 WHERE LIKE
。我有标签,其中一些标签的名称包含字母 "cat":
pgdb=> SELECT * FROM tagging_tag WHERE tagging_tag.name LIKE '%cat%'
ORDER BY tagging_tag.name ASC;
id | name | synonym_id
------+---------------------+------------
68496 | blackcat |
4 | cat |
28461 | catfight |
我似乎有一个名为 "cat" 的标签,但如果我尝试自己获取它,它会失败:
pgdb=> SELECT * FROM tagging_tag WHERE tagging_tag.name = 'cat'
ORDER BY tagging_tag.name ASC;
id | name | synonym_id
---+------+------------
(0 line)
但如果我尝试使用部分 LIKE
,它会起作用:
pgdb=> SELECT * FROM tagging_tag WHERE tagging_tag.name LIKE '%cat'
ORDER BY tagging_tag.name ASC;
id | name | synonym_id
------+---------------------+------------
68496 | blackcat |
4 | cat |
pgdb=> SELECT * FROM tagging_tag WHERE tagging_tag.name LIKE 'cat%'
ORDER BY tagging_tag.name ASC;
id | name | synonym_id
------+----------------+------------
4 | cat |
28461 | catfight |
我试图检查大小,想到了一个不可见的字符但没有机会:
pgdb=> SELECT char_length(name), * FROM tagging_tag WHERE tagging_tag.name LIKE 'cat%'
ORDER BY "tagging_tag"."name" ASC;
char_length | id | name | synonym_id
------------+-------+----------------+------------
3 | 4 | cat |
8 | 28461 | catfight |
我做了几次测试,似乎有些标签可以用 =
获取,有些则不能,而且我找不到它们之间的任何共同点:字母的数量各不相同,它们是所有ASCII小写,ID不分组等
这是一个解释:
EXPLAIN SELECT * FROM tagging_tag WHERE tagging_tag.name = 'cat'
ORDER BY tagging_tag.name ASC;
QUERY PLAN
-------------------------------------------------------------------------------------
Index Scan using tagging_tag_name on tagging_tag (cost=0.29..4.31 rows=1 width=19)
Index Cond: ((name)::text = 'cat'::text)
(2 lignes)
关于 table 的一些背景信息:
pgdb=> \d tagging_tag
Table « public.tagging_tag »
Colonne | Type | Modificateurs
-----------+-----------------------+-------------------------------------
id | integer | non NULL Par défaut, nextval('...
name | character varying(50) | non NULL
synonym_id | integer |
Index :
"tagging_tag_id_pkey" PRIMARY KEY, btree (id)
"tagging_tag_name" UNIQUE, btree (name)
"tagging_tag_synonym_id" btree (synonym_id)
Foreign key contraints :
"tagging_tag_synonym_id_fkey" FOREIGN KEY (synonym_id) REFERENCES tagging_tag(id)
Referenced by :
TABLE "tagging_tag" CONSTRAINT "tagging_tag_synonym_id_fkey"
FOREIGN KEY (synonym_id) REFERENCES tagging_tag(id)
Postgres 版本为 9.3.6。
因为 name LIKE '%cat'
和 name LIKE 'cat%'
都测试了同一行 return 并且它只包含字符串 'cat' 一次(或者是吗?)它遵循逻辑name = 'cat'
也应该 return 同一行。
前导或尾随白色 space 无法解释这一点。
其余解释包括:
一个误解,你用不同的数据库/不同的tables,不同的search_path
或类似的东西进行了测试。
另一种误解:你的字符串中有一个换行符,实际上是这样的:
cat
cat
你错过了第二行?
损坏的索引。 EXPLAIN
输出显示可能使用了哪些索引。重新创建涉及的索引并查看是否可以解决问题。您的问题更新显示它必须是索引 tagging_tag_name
:
REINDEX INDEX tagging_tag_name;
暴力替代方案是:
VACUUM FULL tagging_tag;
重写整个 table 及其上的所有索引(采用独占锁)。
我在 Postgres 上有一个非常简单的查询,它以 WHERE =
失败,但适用于 WHERE LIKE
。我有标签,其中一些标签的名称包含字母 "cat":
pgdb=> SELECT * FROM tagging_tag WHERE tagging_tag.name LIKE '%cat%'
ORDER BY tagging_tag.name ASC;
id | name | synonym_id
------+---------------------+------------
68496 | blackcat |
4 | cat |
28461 | catfight |
我似乎有一个名为 "cat" 的标签,但如果我尝试自己获取它,它会失败:
pgdb=> SELECT * FROM tagging_tag WHERE tagging_tag.name = 'cat'
ORDER BY tagging_tag.name ASC;
id | name | synonym_id
---+------+------------
(0 line)
但如果我尝试使用部分 LIKE
,它会起作用:
pgdb=> SELECT * FROM tagging_tag WHERE tagging_tag.name LIKE '%cat'
ORDER BY tagging_tag.name ASC;
id | name | synonym_id
------+---------------------+------------
68496 | blackcat |
4 | cat |
pgdb=> SELECT * FROM tagging_tag WHERE tagging_tag.name LIKE 'cat%'
ORDER BY tagging_tag.name ASC;
id | name | synonym_id
------+----------------+------------
4 | cat |
28461 | catfight |
我试图检查大小,想到了一个不可见的字符但没有机会:
pgdb=> SELECT char_length(name), * FROM tagging_tag WHERE tagging_tag.name LIKE 'cat%'
ORDER BY "tagging_tag"."name" ASC;
char_length | id | name | synonym_id
------------+-------+----------------+------------
3 | 4 | cat |
8 | 28461 | catfight |
我做了几次测试,似乎有些标签可以用 =
获取,有些则不能,而且我找不到它们之间的任何共同点:字母的数量各不相同,它们是所有ASCII小写,ID不分组等
这是一个解释:
EXPLAIN SELECT * FROM tagging_tag WHERE tagging_tag.name = 'cat'
ORDER BY tagging_tag.name ASC;
QUERY PLAN
-------------------------------------------------------------------------------------
Index Scan using tagging_tag_name on tagging_tag (cost=0.29..4.31 rows=1 width=19)
Index Cond: ((name)::text = 'cat'::text)
(2 lignes)
关于 table 的一些背景信息:
pgdb=> \d tagging_tag
Table « public.tagging_tag »
Colonne | Type | Modificateurs
-----------+-----------------------+-------------------------------------
id | integer | non NULL Par défaut, nextval('...
name | character varying(50) | non NULL
synonym_id | integer |
Index :
"tagging_tag_id_pkey" PRIMARY KEY, btree (id)
"tagging_tag_name" UNIQUE, btree (name)
"tagging_tag_synonym_id" btree (synonym_id)
Foreign key contraints :
"tagging_tag_synonym_id_fkey" FOREIGN KEY (synonym_id) REFERENCES tagging_tag(id)
Referenced by :
TABLE "tagging_tag" CONSTRAINT "tagging_tag_synonym_id_fkey"
FOREIGN KEY (synonym_id) REFERENCES tagging_tag(id)
Postgres 版本为 9.3.6。
因为 name LIKE '%cat'
和 name LIKE 'cat%'
都测试了同一行 return 并且它只包含字符串 'cat' 一次(或者是吗?)它遵循逻辑name = 'cat'
也应该 return 同一行。
前导或尾随白色 space 无法解释这一点。
其余解释包括:
一个误解,你用不同的数据库/不同的tables,不同的
search_path
或类似的东西进行了测试。另一种误解:你的字符串中有一个换行符,实际上是这样的:
cat cat
你错过了第二行?
损坏的索引。
EXPLAIN
输出显示可能使用了哪些索引。重新创建涉及的索引并查看是否可以解决问题。您的问题更新显示它必须是索引tagging_tag_name
:REINDEX INDEX tagging_tag_name;
暴力替代方案是:
VACUUM FULL tagging_tag;
重写整个 table 及其上的所有索引(采用独占锁)。