MYSQL TEXT类型列的查找

16

我的表/模型有一个TEXT类型的列,当在模型本身上过滤记录时,AR where会生成正确的SQL并返回正确的结果,这就是我的意思:

MyNamespace::MyValue.where(value: 'Good Quality')

生成此 SQL 语句:

SELECT `my_namespace_my_values`.* 
FROM `my_namespace_my_values` 
WHERE `my_namespace_my_values`.`value` = '\\\"Good Quality\\\"'

再看一个例子,我正在连接MyNamespace::MyValue并在同一value列上对另一个模型(具有到my_values的关系)进行过滤。请查看此查询(query #2):

OtherModel.joins(:my_values).where(my_values: { value: 'Good Quality' })

这不会产生正确的查询结果,它将value列过滤为字符串列而不是文本列,因此产生了不正确的结果,例如(仅粘贴相关部分):

WHERE my_namespace_my_values`.`value` = 'Good Quality'

现在我可以通过在我的 AR where 子句中使用 LIKE 来解决这个问题,这将产生正确的结果,但查询略有不同。这就是我的意思:

OtherModel.joins(:my_values).where('my_values.value LIKE ?, '%Good Quality%')

最后来到我的问题。 这是什么,它是如何为模型上的哪个位置(对于文本列类型)生成的?

WHERE `my_namespace_my_values`.`value` = '\\\"Good Quality\\\"'

也许最重要的问题是,使用哪种方式在性能方面有何差异:

WHERE `my_namespace_my_values`.`value` = '\\\"Good Quality\\\"'

还有这个:

(my_namespace_my_values.value LIKE '%Good Quality%')

更重要的是,我如何让我的具有连接的查询(查询 #2)产生以下类似的结果:

WHERE `my_namespace_my_values`.`value` = '\\\"Good Quality\\\"'

你正在使用哪个Rails插件? - Rick James
@RickJames 没有插件 - ant
那么是什么生成了所有的反斜杠和引号? - Rick James
你使用的是哪个版本的Rails和MySQL? - ragav ramachandran
Active Record 我猜是 @RickJames,Rails 4.2.10,这里是关于 MySQL 的信息 "innodb_version", "5.6.27", ["protocol_version", "10"], ["slave_type_conversions", ""], ["version", "5.6.27-log"], ["version_comment", "MySQL Community Server (GPL)"], ["version_compile_machine", "x86_64"], ["version_compile_os", "Linux"] - ant
4个回答

5
(部分答案--从MySQL方面接近。) 匹配与不匹配的情况 情况1:(我不知道额外的反斜杠和引号是从哪里来的。)
WHERE `my_namespace_my_values`.`value` = '\\\"Good Quality\\\"'

\"Good Quality\"               -- matches
Good Quality                   -- does not match
The product has Good Quality.  -- does not match

案例2:(在“value”中的任何地方找到“Good Quality”)
注:该段文字涉及IT技术,为保证翻译准确性,请留意上下文结合理解。
WHERE my_namespace_my_values.value LIKE '%Good Quality%'

\"Good Quality\"               -- matches
Good Quality                   -- matches
The product has Good Quality.  -- matches

案例3:

WHERE `my_namespace_my_values`.`value` = 'Good Quality'

\"Good Quality\"               -- does not match
Good Quality                   -- matches
The product has Good Quality.  -- does not match

性能:

  • 如果value声明为TEXT,则所有情况都很慢。
  • 如果value没有被索引,所有情况都很慢。
  • 如果valueVARCHAR(255)(或更小)并且已经被索引,情况1和3会更快。它可以快速找到一行而不是检查所有行。

换句话说:

  • 使用一个前置通配符(%)的LIKE操作很慢。
  • 对于性能而言,对该列进行索引非常重要,但TEXT无法被索引。

2

这是什么,以及它是如何为模型中的哪个位置(针对文本列类型)生成的?

这是在Active Records(Arel)词法引擎后面生成的。请参见下面关于您第二个问题的答案。

在性能方面,使用...有什么区别?

"="通过整个字符串/块比较进行匹配,而LIKE通过字符匹配。

在我的项目中,我有包含数百万行的表格,根据我的经验,在查询中使用"="或regexp比使用LIKE更快。

如何使我的连接查询(查询#2)产生以下结果...

您可以尝试这样做:

OtherModel.joins(:my_values).where(OtherModel[:value].eq('\\\"Good Quality\\\"'))

2

我认为这可能很有帮助。

要搜索 \n,请将其指定为 \n。要搜索 \,请将其指定为 \\。这是因为解析器会将反斜杠剥离一次,然后在进行模式匹配时再次剥离反斜杠,留下一个单独的反斜杠进行匹配。

链接

LIKE 和 = 是不同的运算符。

= 是一个操作数,它可以用于数字和字符串。当比较字符串时,比较运算符会比较整个字符串。

LIKE 是一个字符串运算符,它逐个字符比较。

mysql> SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
+-----------------------------------------+
| 'ä' LIKE 'ae' COLLATE latin1_german2_ci |
+-----------------------------------------+
|                                       0 |
+-----------------------------------------+
mysql> SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
+--------------------------------------+
| 'ä' = 'ae' COLLATE latin1_german2_ci |
+--------------------------------------+
|                                    1 |
+--------------------------------------+

2
'

“=”操作符是在查找精确匹配,而“LIKE”操作符更像正则表达式中的“*”,进行模式匹配。“%”与“*”类似。

如果有以下条目:

  1. Good Quality
  2. More Good Quality

只有“LIKE”才能得到两个结果。

关于转义字符串,我不确定这是在哪里生成的,但它看起来像是一种标准化的转义方式,以使其对SQL有效。

'

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