【问题标题】:MySQL Query slow on server but fast on VMMySQL 查询在服务器上慢,但在 VM 上快
【发布时间】:2015-05-16 04:52:10
【问题描述】:

我遇到的问题是,在分配了 4GB 的 VirtualBox 机器上查询耗时不到一秒,但在分配了 16GB 的实际服务器上查询耗时超过 20 秒。

首先是架构的相关部分:

accounts (about 13k records)
(
    act_id
)

contacts (about 13k records)
(
    cnt_id,
    cnt_description,
    cnt_hascontact_id,
    cnt_hascontact_type
)

addresses (about 13k records)
(
    add_id,
    add_description,
    add_hasaddress_id,
    add_hasaddress_type
)

这是我正在运行的查询:

SELECT 
    act_id, 
    act_name, 
    act_short, 
    act_ptnumber, 
    cnt_firstname, 
    cnt_lastname, 
    cnt_phone, 
    cnt_email, 
    add_street1, 
    add_city, 
    add_state, 
    add_zip 
FROM accounts  
INNER JOIN addresses ON act_id = add_hasaddress_id  
INNER JOIN contacts ON act_id = cnt_hascontact_id
WHERE act_name LIKE '%<some string>%'
AND cnt_description = 1
AND add_description = 3
GROUP BY act_id
LIMIT 100;

现在。联系人和地址表是多态的,因此这里除了accounts.act_id 之外没有索引。我认为这很重要,但同样,我的 VM 需要不到一秒钟的时间来运行查询。

我在每台机器上打开了性能分析,发现在真实服务器上花了这么长时间是“复制到 tmp 表”。这本身可能需要 20 秒。我觉得奇怪的是虚拟机服务器甚至没有执行这一步。所以,我明白为什么它要快得多了。

当然,真正的服务器正在使用中,因此数据库一次会受到大约 100 个左右的用户的访问,而我的虚拟机则只运行我的查询。我尝试将 'tmp_table_size' 和 'max_heap_table_size' 的值增加到 1024M,但这没有任何作用。

有没有人知道发生了什么或者我该如何解决这个问题?提前感谢您的帮助。

编辑:

所有表都是 InnoDB

一些配置:

虚拟机:

tmpdir                               = /var/lib/mysqltmp
table-definition-cache               = 4096
table-open-cache                     = 4096
max-connections                      = 400
max-connect-errors                   = 1000000
max-allowed-packet                   = 16M
skip-name-resolve
wait-timeout                         = 600
key-buffer-size                      = 32M
myisam-sort-buffer-size              = 128M
innodb-file-format                   = Barracuda

服务器:

tmpdir                          = /var/lib/mysqltmp
skip-name-resolve
sql-mode                        = NO_ENGINE_SUBSTITUTION
table-open-cache                = 4096
table-definition-cache          = 4048
tmp-table-size                  = 2048M
max-heap-table-size             = 2048M
back-log                        = 100
max-connect-errors              = 10000
max-allowed-packet              = 64M
interactive-timeout             = 3600
wait-timeout                    = 600
default-storage-engine          = InnoDB
innodb                          = FORCE
key-buffer-size                 = 64M
myisam-sort-buffer-size         = 128M

如果没有配置,则为默认配置。

编辑 2:

这是每个服务器上查询的EXPLAIN SELECT

虚拟机:

1   SIMPLE  contacts    ref contacts_cnt_description_foreign    contacts_cnt_description_foreign    4   const   5724    Using temporary; Using filesort
1   SIMPLE  accounts    eq_ref  PRIMARY,accounts_act_name_unique,accounts_act_type_foreign,accounts_act_businesstype_foreign,accounts_act_parent_foreign    PRIMARY 4   supportnet.contacts.cnt_hascontact_id   1   Using where
1   SIMPLE  addresses   ALL addresses_add_description_foreign               12548   Using where; Using join buffer (Block Nested Loop)

服务器:

1   SIMPLE  contacts    ref contacts_cnt_description_foreign    contacts_cnt_description_foreign    4   const   6155    Using temporary; Using filesort
1   SIMPLE  addresses   ALL addresses_add_description_foreign               12903   Using where; Using join buffer
1   SIMPLE  accounts    eq_ref  PRIMARY PRIMARY 4   supportnet.contacts.cnt_hascontact_id   1   Using where

【问题讨论】:

  • 您是否考虑过从 RAM 磁盘运行 MySQL 中的 tmp 表?这是一篇不错的文章:2bits.com/articles/… 另一件事是启用和使用查询缓存?
  • 在测试速度时,使用SELECT SQL_NO_CACHE ... 确保查询缓存不满足您的查询。
  • 存储引擎,存储引擎配置?没有提到那些?
  • 您到底在寻找什么数据?数据库使用 InnoDB。我添加了一些相关的配置信息。

标签: mysql


【解决方案1】:

InnoDB——很好。但我没有看到 innodb_buffer_pool_size 的设置。这很重要,应该占可用 RAM 的 70%。由于 RAM 不同,并且您可能使用不同的版本(具有不同的默认值),请查看 SHOW VARIABLES LIKE 'innodb%'; 还有其他重要的设置可能会以不同的方式默认。

如果生产机器上正在运行其他查询,它们可能正在破坏缓存(buffer_pool)。这可能会导致您所看到的。如果还有其他“大”查询,让我们关注它们。

数据集的大小和内容是否相同?

不要使用 RAM 磁盘 - 备用空间在 buffer_pool 中更有用。而且,如果您的查询太大,它会崩溃。

'tmp_table_size' 和 'max_heap_table_size' 为 1024M

那很危险!这可能会导致 RAM 用完,进而导致“交换”,这对于性能而言比将它们设置得更低。

编辑(基于解释)

添加INDEX(add_hasaddress_id) -- 注意ALL 在到达addresses 时是怎么说的?这意味着没有索引是有用的。如有其他问题,请提供SHOW CREATE TABLE

【讨论】:

  • innodb_buffer_pool_size 设置为 128M,但我将其删除以匹配我的 VM(默认)以尝试使它们匹配。应该更高吗? VM 使用 5.6.22,而服务器使用 5.5.36。那里可能存在差异。数据大致相同。 VM 只是充当我克隆数据库的测试环境。我已经删除了 tmp 表配置的东西。我只是想尝试一下,但它什么也没做。
  • 4GB机器1500M; 11G 为 16GB 机器。版本差异不是大问题。在每台机器上做EXPLAIN SELECT...;让我们看看输出。 (可能存在细微差别。)当实际服务器运行查询太慢时,它有多忙?是否同时插入/更新表?
  • 我重新添加了池大小并将其设置为 8GB。那没什么区别。我将解释选择添加到 OP。有一些差异,但我真的不知道如何解释它们。
【解决方案2】:

由于每个表中的记录如此之少,因此不可能花费 20 秒,也许是因为您忘记了索引。您应该检查诸如锁、防火墙阻塞或网络问题之类的东西

【讨论】:

    【解决方案3】:

    最终的解决方案是升级 mysql。一旦我从 5.5 迁移到 5.6,这个问题就消失了。

    【讨论】:

      猜你喜欢
      • 2013-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-21
      • 1970-01-01
      • 2014-06-26
      • 2013-01-15
      • 1970-01-01
      相关资源
      最近更新 更多