选择 VARCHAR 字段时 JOIN 性能非常慢
JOIN performance very slow when selecting VARCHAR field
我遇到了一个查询难题,我无法找出它执行如此糟糕的原因。
请看以下查询和查询次数(使用HeidiSQL):
SELECT p.TID, a.TID
FROM characters AS p JOIN account a ON p.AccountId = a.TID;
=> rows: 57.879 Query time: 0.063 sec. (+ 0.328 sec. network)
解释:
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+--------------------------+
| 1 | SIMPLE | a | index | TID | WebAccountId | 5 | NULL | 21086 | Using index |
| 1 | SIMPLE | p | ref | AccountId | AccountId | 5 | dol.a.TID | 1 | Using where; Using index |
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+--------------------------+
这很快,但是一旦我 select 来自 table characters
的 VARCHAR(255) 字段,它就会变得非常慢。查看网络时间。
SELECT p.TID, a.TID, p.LastName
FROM characters AS p JOIN account a ON p.AccountId = a.TID;
=> rows: 57.879 Query time: 0.219 sec. (+ 116.234 sec. network)
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+-------------+
| 1 | SIMPLE | a | index | TID | WebAccountId | 5 | NULL | 21086 | Using index |
| 1 | SIMPLE | p | ref | AccountId | AccountId | 5 | dol.a.TID | 1 | Using where |
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+-------------+
查询时间仍然不错,但网络时间变得难以忍受。
有人可能认为它是由 p.LastName
的传输引起的,但看到查询 没有连接 :
SELECT p.TID, p.LastName
FROM characters AS p
=> rows: 57.881 Query time: 0.063 sec. (+ 0.578 sec. network)
+----+-------------+-------+------+---------------+------+---------+------+-------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------+
| 1 | SIMPLE | p | ALL | NULL | NULL | NULL | NULL | 59800 | |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------+
知道这里发生了什么吗?我不知道如何解决这个问题。
编辑:
为每个查询添加了解释输出。
如果重要,它是 mysql 5.1.72-community
Edit2: 从命令行测试。同样的表现。如果我查看 mysql 进程列表,我会看到 Sending data
表示性能不佳的查询。该查询最初用于 ASP.NET web 应用程序,性能非常糟糕。这就是为什么我使用 HeidiSQL 进行调查的原因。我肯定会排除 HeidiSQL 的问题。
Edit3 Mysql Workbench 中的测试结果:
我在这里找到了罪魁祸首。我在默认设置下使用 mysql 5.1.72 和 InnoDB。
这意味着它使用了一个只有 8MB 的 InnoDB 缓冲池
innodb_buffer_pool_size=8M
Mysql 被迫将结果写入磁盘,因为一旦我将 VARCHAR 字段添加到 select 子句,它就无法将结果保存在内存中进行传输。 Join 似乎对该缓冲区的内存使用施加了更大的压力。
在我将缓冲区大小更改为 1G 之后,问题就消失了。
innodb_buffer_pool_size=1G
mysql 开始后的第一个请求仍然有点慢,但后续查询非常快。
所以这基本上是 mysql 服务器配置错误。
我遇到了一个查询难题,我无法找出它执行如此糟糕的原因。
请看以下查询和查询次数(使用HeidiSQL):
SELECT p.TID, a.TID
FROM characters AS p JOIN account a ON p.AccountId = a.TID;
=> rows: 57.879 Query time: 0.063 sec. (+ 0.328 sec. network)
解释:
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+--------------------------+
| 1 | SIMPLE | a | index | TID | WebAccountId | 5 | NULL | 21086 | Using index |
| 1 | SIMPLE | p | ref | AccountId | AccountId | 5 | dol.a.TID | 1 | Using where; Using index |
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+--------------------------+
这很快,但是一旦我 select 来自 table characters
的 VARCHAR(255) 字段,它就会变得非常慢。查看网络时间。
SELECT p.TID, a.TID, p.LastName
FROM characters AS p JOIN account a ON p.AccountId = a.TID;
=> rows: 57.879 Query time: 0.219 sec. (+ 116.234 sec. network)
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+-------------+
| 1 | SIMPLE | a | index | TID | WebAccountId | 5 | NULL | 21086 | Using index |
| 1 | SIMPLE | p | ref | AccountId | AccountId | 5 | dol.a.TID | 1 | Using where |
+----+-------------+-------+-------+---------------+--------------+---------+-----------+-------+-------------+
查询时间仍然不错,但网络时间变得难以忍受。
有人可能认为它是由 p.LastName
的传输引起的,但看到查询 没有连接 :
SELECT p.TID, p.LastName
FROM characters AS p
=> rows: 57.881 Query time: 0.063 sec. (+ 0.578 sec. network)
+----+-------------+-------+------+---------------+------+---------+------+-------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------+
| 1 | SIMPLE | p | ALL | NULL | NULL | NULL | NULL | 59800 | |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------+
知道这里发生了什么吗?我不知道如何解决这个问题。
编辑: 为每个查询添加了解释输出。 如果重要,它是 mysql 5.1.72-community
Edit2: 从命令行测试。同样的表现。如果我查看 mysql 进程列表,我会看到 Sending data
表示性能不佳的查询。该查询最初用于 ASP.NET web 应用程序,性能非常糟糕。这就是为什么我使用 HeidiSQL 进行调查的原因。我肯定会排除 HeidiSQL 的问题。
Edit3 Mysql Workbench 中的测试结果:
我在这里找到了罪魁祸首。我在默认设置下使用 mysql 5.1.72 和 InnoDB。
这意味着它使用了一个只有 8MB 的 InnoDB 缓冲池
innodb_buffer_pool_size=8M
Mysql 被迫将结果写入磁盘,因为一旦我将 VARCHAR 字段添加到 select 子句,它就无法将结果保存在内存中进行传输。 Join 似乎对该缓冲区的内存使用施加了更大的压力。
在我将缓冲区大小更改为 1G 之后,问题就消失了。
innodb_buffer_pool_size=1G
mysql 开始后的第一个请求仍然有点慢,但后续查询非常快。
所以这基本上是 mysql 服务器配置错误。