【问题标题】:col LIKE BINARY 'val%' much slower than col LIKE 'val%' . Why?col LIKE BINARY 'val%' 比 col LIKE 'val%' 慢得多。为什么?
【发布时间】:2019-09-07 13:18:15
【问题描述】:

我还有来自this question 的后续跟进。尽管LIKE 模式搜索(由于排序规则集)使用索引并且比LIKE BINARY 快​​得多,但对这两个查询进行解释似乎表明两个查询都使用索引。

explain select count(*) from TransactionApp_transactions where merchantId like 'VCARD000%'

| id | select_type | table                       | type  | possible_keys                        | key                                 | key_len | ref  | rows     | Extra                    |
+----+-------------+-----------------------------+-------+--------------------------------------+--------------------------------------+---------+------+----------+--------------------------+
|  1 | SIMPLE      | TransactionApp_transactions | range | TransactionApp_transactions_fc3e7169 | TransactionApp_transactions_fc3e7169 | 767     | NULL | 12906834 | Using where; Using index |

我得到与explain select count(*) from TransactionApp_transactions where merchantId like binary 'VCARD000%'; 完全相同的EXPLAIN 输出(rows 是一个稍小的数字)

key 列包含两个 EXPLAIN 输出的索引名称,但 LIKE BINARY 需要 26 秒,而简单的 LIKE 只需 2 秒。

【问题讨论】:

  • 请将代码发布为文本而不是图像
  • 很抱歉。现在用文字编辑我的问题。
  • stackoverflow.com/questions/8097996/… 你能检查一下这个答案吗
  • @AshishMahajan - 是的,我知道LIKE BINARY 不使用索引,因为排序规则集是非二进制的,但为什么EXPLAIN 输出说它使用索引?跨度>
  • 你有merchantId的索引吗?请提供SHOW CREATE TABLE

标签: mysql database collation database-indexes


【解决方案1】:

在给定column 上的索引的情况下,使用WHERE column LIKE 'value%' 的查询比使用WHERE column LIKE BINARY 'value%' 的查询快得多。这完全是意料之中的。为什么?

LIKE 'value%' 过滤器使用索引来查找匹配的行。它假定要匹配的 'value%' 文本使用与列相同的排序规则。而且,索引使用它们索引的列的排序规则;排序规则被烘焙到索引中。在列包含不区分大小写的文本的情况下,这使得搜索'value%''Value%''VALUE%' 都可以使用索引,即使在搜索中必须忽略大小写。

当您使用LIKE BINARY 而不是LIKE 时,您声明了搜索所需的排序规则。您告诉 MySQL 的查询计划器它不能使用它拥有的索引,因为该索引的内置排序规则对您的查询没有用。所以它会进行全表扫描。这很慢。

如果您需要区分大小写的搜索,请在创建(或更改)表时为该列声明区分大小写的排序规则。那么 LIKE 过滤器将区分大小写。

要获得区分大小写的排序规则,您可以像这样创建表(您没有显示表定义,所以这是猜测)。

  CREATE TABLE tbl (
     ...
     mid VARCHAR(255) CHARACTER SET latin1 COLLATE latin1_bin,
     ...
  )

或者您可以像这样更改列以具有区分大小写的排序规则。

 ALTER TABLE tbl MODIFY mid VARCHAR(255) COLLATE latin1_bin;

备注:WHERE col LIKE BINARY 'value%' 是一种奇怪的查询方式。这可能就是为什么 EXPLAIN 不能很好地处理它的原因。

【讨论】:

  • 谢谢!我还想知道编写查询的合适方法是什么,而不是 WHERE col LIKE BINARY 'value%',这是 Django 从其 ORM 生成的(ORM 等价物是 col__startswith='value')。
【解决方案2】:

对所有这些都使用 same 排序规则:

  • 连接数据库
  • 客户端中的字节数
  • 正在测试的列。

可能merchantId 是(或_应该是)CHARACTER SET ascii。这可能与其他字符串不一致(utf8mb4 是首选的名称等)。

但首先,您是如何连接的?表定义是什么?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-10
    • 2012-11-04
    • 1970-01-01
    相关资源
    最近更新 更多