【问题标题】:simple SQL statement takes longer time to execute [duplicate]简单的SQL语句需要更长的时间来执行[重复]
【发布时间】:2025-11-30 19:55:01
【问题描述】:

可能重复:
Disadvantages of quoting integers in a Mysql query?

我在 MYSql 数据库上有一个非常简单的名为 Device 的表。

+-----------------------------------+--------------+------+-----+----------------+
| Field                             | Type         | Null | Key | Extra          |
+-----------------------------------+--------------+------+-----+----------------+
| DTYPE                             | varchar(31)  | NO   |     |                |
| id                                | bigint(20)   | NO   | PRI | auto_increment |
| dateCreated                       | datetime     | NO   |     |                |
| dateModified                      | datetime     | NO   |     |                |
| phoneNumber                       | varchar(255) | YES  | MUL |                |
| version                           | bigint(20)   | NO   |     |                |
| oldPhoneNumber                    | varchar(255) | YES  |     |                |
+-----------------------------------+--------------+------+-----+----------------+

此表有超过 10 万条记录。我正在运行一个非常简单的查询

select * from AttDevice where phoneNumber = 5107357058;

这个查询大约需要 4-6 秒,但是当我稍微改变这个查询时,如下所示。

select * from AttDevice where phoneNumber = '5107357058';

执行几乎不需要时间。 请注意,phoneNumber 列是 varchar。我不明白为什么前一种情况需要更长的时间而后来不需要。这两个查询之间的区别在于单引号。 如果是这样,MYSQL 是否会以不同的方式处理这些查询,那为什么?

编辑 1

我使用了EXPLAIN 并得到了以下输出,但不知道如何解释这两个结果。

mysql> EXPLAIN select * from AttDevice where phoneNumber = 5107357058;
+----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+
| id | select_type | table     | type | possible_keys                         | key  | key_len | ref  | rows    | Extra       |
+----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+
|  1 | SIMPLE      | Device    | ALL  | phoneNumber,idx_Device_phoneNumber | NULL | NULL    | NULL | 6482116 | Using where |
+----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

mysql> EXPLAIN select * from AttDevice where phoneNumber = '5107357058';
+----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+
| id | select_type | table     | type | possible_keys                         | key         | key_len | ref   | rows | Extra       |
+----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+
|  1 | SIMPLE      |   Device  | ref  | phoneNumber,idx_Device_phoneNumber    | phoneNumber | 258     | const |    2 | Using where |
+----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+
1 row in set (0.00 sec)

有人可以解释一下 EXPLAIN 查询输出中的键、key_len 和行吗?

【问题讨论】:

  • 您是否尝试过EXPLAIN 查询?那应该回答你的问题。
  • 是否有可能第二次执行速度更快,因为它在内存中缓存了部分结果?
  • 问:你试过“解释”吗?它说了什么w.r.t。到可能的键、键、键长度等?请张贴两个“解释”。问:为什么是“sql-server”标签?
  • 在我的拙见中,当与phoneNumber 比较的值是另一种数据类型(在您的示例中为无符号整数)时,该值首先转换为VARCHAR,这可能是原因这需要额外的时间。
  • 如果这是mysql,为什么要标记为sql-server?

标签: mysql sql


【解决方案1】:

1) 感谢您的“解释”。我们都(包括你,我敢肯定)知道问题在于 mysql 必须将整数转换为字符串,并且必须为每一行都这样做。但你的“解释”证明了这一点。

2) 这是一篇关于 EXPLAIN 的精彩简短文章:

*possible_keys* 显示哪些索引适用于该查询以及 key 告诉我们哪些是实际使用的-...最后 rows 条目告诉 我们 MySQL 必须查看多少行才能找到结果集。

Search value:   key:        type:  ref:   rows:  
-------------   ---         ----   ----   ----
5107357058      NULL        ALL    NULL   6482116
'5107357058'    phoneNumber ref    const  2

3) “ref”列是“与索引比较的列”。在第二种情况下,将字符串文字(“常量”)“5107357058”与键“phoneNumber”进行比较。在第一种情况下,没有可用的键(因为您的搜索条件是完全不同的类型);因此 "ref" 为 NULL。

4) “类型”列是“连接类型”。 “Ref”表示“从该表中读取所有具有匹配索引值的行”(在本例中为 2 行)。 “ALL”包含“全表扫描”。在这种情况下,这意味着 600 万行。

5) 这是“解释”的 mysql 文档:

【讨论】:

    【解决方案2】:

    您通过不引用电话号码欺骗了 MySQL 做出了错误的选择。考虑:

    1. 列定义为varchar
    2. 在第一种(未加引号的)情况下,您将值提供为整数(长整数)。我原以为 MySQL 可以解决这个问题,但显然它没有,并进行了全表扫描。
    3. 在第二种(引用的)案例中,您提供了正确数据类型(字符)的搜索键,MySQL 选择了索引而不是全表扫描。

    【讨论】:

      【解决方案3】:

      使用数字作为操作数时不能使用 varchar 索引,摘自 implicit type conversions 上的精美文档:

      对于字符串列与数字的比较,MySQL 不能使用列上的索引来快速查找值。如果 str_col 是索引字符串列,则在以下语句中执行查找时不能使用索引:

      SELECT * FROM tbl_name WHERE str_col=1;

      这样做的原因是有许多不同的字符串可以转换为值 1,例如 '1'、'1' 或 '1a'。

      【讨论】:

        【解决方案4】:

        我相信 MySQL 在第一个示例中必须将数字转换为 varchar。在第二个例子中它没有。我猜这就是差异的来源。

        【讨论】:

        • 是的,即使我也这么怀疑。我注意到这里还有一件事,对于第一个查询,Explain 输出中的行数有 6482116 行,而对于第二个查询,它只有 2 行。
        • 它没有使用第一个中的密钥。这可能是因为您没有在 varchar 标准周围使用单引号。如果你这样做,它将正确使用密钥并运行得更快。
        • 将整数值转换为 varchar 值相差 4-6 秒?
        • 这是因为它没有使用密钥(索引)。一定是因为条件的类型不正确。
        • 在第二种情况下,它使用电话号码键。首先它没有使用任何。
        【解决方案5】:

        第一个示例逐个查看表格,另一个使用索引。

        http://dev.mysql.com/doc/refman/5.0/en/show-columns.html
        如果 Key 为 MUL,则允许在列中多次出现给定值。该列是可以包含 NULL 值的非唯一索引或唯一值索引的第一列。

        因此,第二个查询不是扫描所有空值,而是专门寻找非空值,这可以加快处理速度。

        ....我想。

        【讨论】: