我遇到的问题是,在分配了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 table&#39;。这可能需要20秒。我觉得奇怪的是VM服务器甚至不执行这一步骤。所以,我明白为什么它会这么快。
当然,真正的服务器正在使用中,因此数据库一次被大约100个左右的用户所击中,而我的VM只运行我的查询。我尝试增加&t; tmp_table_size&#39;的值。和&#39; max_heap_table_size&#39;至1024M,但没有做任何事情。
有没有人知道发生了什么或我如何解决这个问题?提前感谢您的帮助。
编辑:
所有表格都是InnoDB
一些conf:
VM:
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 :
VM:
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
答案 0 :(得分:0)
InnoDB - 很好。但我没有看到innodb_buffer_pool_size的设置。这很重要,应该是可用 RAM的70%左右。由于RAM不同,并且您可能使用不同的版本(具有不同的默认值),请查看SHOW VARIABLES LIKE 'innodb%';
还有其他重要设置可能会有不同的默认设置。
如果生产计算机上正在运行其他查询,则可能会破坏缓存(buffer_pool)。这可能会导致你看到的。如果还有其他&#34;大&#34;查询,让我们关注它们。
数据集的大小和内容是否相同?
不要使用RAM磁盘 - 备用空间在buffer_pool中更有用。而且,如果你的查询过于庞大,它就会崩溃。
&#39; tmp_table_size的&#39;和&#39; max_heap_table_size&#39;到1024M
这很危险!它可能导致RAM耗尽,这会导致交换&#34;对于性能而言, 更糟糕,而不是将它们设置得更低。
编辑(基于EXPLAINs)
添加INDEX(add_hasaddress_id)
- 请注意ALL
进入addresses
后如何说SHOW CREATE TABLE
?这意味着没有索引是有用的。如果还有其他问题,请向我们提供{{1}}。
答案 1 :(得分:0)
每张表中的记录如此之少,如果你忘记了索引,就不可能花20秒钟。您应该检查锁,防火墙堵塞或网络问题等内容
答案 2 :(得分:0)
最终的解决方案最终是升级mysql。一旦我从5.5移动到5.6,这个问题就消失了。