MySQL 性能调优 + 查询卡在“复制到 tmp 表”上

5 mysql performance

问题标题的后半部分(停留在“复制到 tmp 表”上的查询)已经解决了很多次,我花了很多时间研究这个问题。如果你们能帮助我得出结论,我将不胜感激——尤其是在我设置了特定服务器的情况下。

服务器快速概览:
- 具有 2 个内核和 64 GB RAM 的专用服务器
- 仅运行 MySQL

设置没有任何调整,所以当前的配置在某种程度上是遥远的。希望你的责骂可以提供知识。

服务器上运行的 Web 应用程序是一个包含 25.000 多种产品的 Magento 站点。最令人头疼的查询是生成站点地图的查询。

目前,以下查询在“复制到 tmp 表”上已卡住了一个多小时:

注意:我真的不需要关于如何通过优化此查询来提高性能的输入,我宁愿看看我可以从已经存在的查询中节省多少查询时间。

SELECT DISTINCT `e`.`entity_id`, `ur`.`request_path` AS `url`, `stk`.`is_in_stock` FROM `catalog_product_entity` AS `e`
INNER JOIN `catalog_product_website` AS `w` ON e.entity_id=w.product_id
LEFT JOIN `core_url_rewrite` AS `ur` ON e.entity_id=ur.product_id AND ur.category_id IS NULL AND ur.store_id='1' AND ur.is_system=1
INNER JOIN `catalog_category_product_index` AS `cat_index` ON e.entity_id=cat_index.product_id AND cat_index.store_id='1' AND cat_index.category_id in ('2', '3', '68', '86', '145', '163', '182', '196', '198', '214', '249', '252', '285', '286', '288', '289', '290', '292', '549') AND cat_index.position!=0
INNER JOIN `cataloginventory_stock_item` AS `stk` ON e.entity_id=stk.product_id AND stk.is_in_stock=1
INNER JOIN `catalog_product_entity_int` AS `t1_visibility` ON e.entity_id=t1_visibility.entity_id AND t1_visibility.store_id=0
LEFT JOIN `catalog_product_entity_int` AS `t2_visibility` ON t1_visibility.entity_id = t2_visibility.entity_id AND t1_visibility.attribute_id = t2_visibility.attribute_id AND t2_visibility.store_id='1'
INNER JOIN `catalog_product_entity_int` AS `t1_status` ON e.entity_id=t1_status.entity_id AND t1_status.store_id=0
LEFT JOIN `catalog_product_entity_int` AS `t2_status` ON t1_status.entity_id = t2_status.entity_id AND t1_status.attribute_id = t2_status.attribute_id AND t2_status.store_id='1' WHERE (w.website_id='1') AND (t1_visibility.attribute_id='102') AND ((IF(t2_visibility.value_id > 0, t2_visibility.value, t1_visibility.value)) IN(3, 2, 4)) AND (t1_status.attribute_id='96') AND ((IF(t2_status.value_id > 0, t2_status.value, t1_status.value)) IN(1))  
Run Code Online (Sandbox Code Playgroud)

相关配置:

服务器缓冲区:

max_connections = 1500;  
key_buffer_size = 22G;  
innodb_buffer_pool_size = 16G;  
innodb_additional_mem_pool_size = 2G;  
innodb_log_buffer_size = 400M;  
query_cache_size = 64M;  
Run Code Online (Sandbox Code Playgroud)

每个线程缓冲区:

read_buffer_size = 2M;  
read_rnd_buffer_size = 16M;  
sort_buffer_size = 128M;  
thread_stack = 192K;  
join_buffer_size = 8M;  
Run Code Online (Sandbox Code Playgroud)

问题:对你们中的任何人来说,这些变量中是否有任何一个看起来很遥远?

上述内存限制将允许我使用比我的系统上实际安装的内存多 130% 的内存。显然,有些事情必须改变。

根据MySQLTuner Perl 脚本,我目前有使用的危险:
总缓冲区:40.7G 全局 + 每个线程 28.2M(1500 个最大线程)
最大可能内存使用量:82.0G(已安装 RAM 的 130%)

问题:上述变量的最大性能提升是什么,或者:增加总服务器缓冲区限制或每个线程缓冲区限制是否更有用?

似乎对“复制到 tmp 表”影响最大的两个变量是:
- tmp_table_size
- max_heap_table_size

我的都设置为0.25G

问题:对于那些变量有什么特别的建议吗?

有两个建议的修复似乎比其他修复更多:
- 终止进程。做冲洗表。
- 杀死进程。修复/优化表。

问题:您认为以上两个建议的解决方案中哪一个最可行?

小智 1

该查询肯定需要优化,因为“DISTINCT”部分强制创建临时表。

如果您确实不想触及查询(这是一个错误),那么您的另一个选择是为您的 tmp 文件创建 RAM 磁盘 (tmpfs)。该查询仍将创建临时表,但它将避免磁盘 I/O 部分。

希望这可以帮助。