【问题标题】:MySQL performance issue on a simple join with big tables与大表进行简单连接时的 MySQL 性能问题
【发布时间】:2017-03-17 19:02:13
【问题描述】:

我正在将 PHP 应用程序从 MSSQL Server 迁移到 MySQL,但我遇到了一个简单的查询,MSSQL Server 持续 0.5 秒,MySQL 持续 50 秒。有任何想法吗?索引?服务器配置? MySQL 服务器硬件等于或优于 MSSQL 服务器。

表结构

两者都是 InnoDB:

CREATE TABLE `tb1` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `nec` INT(11),
    `start_date` DATETIME(6) NOT NULL,
    `end_date` DATETIME(6) NOT NULL,
    PRIMARY KEY (`id`),
    INDEX `IX_nec` (`nec`)
);

CREATE TABLE `tb2` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `nec` INT(11) NOT NULL,
    `start_date` DATETIME(6) NOT NULL,
    `end_date` DATETIME(6) NOT NULL,
    PRIMARY KEY (`id`),
    INDEX `IX_nec` (`nec`)
);

这些表很大。 Tb1 大约有 300.000 行,tb2 大约有 400.000 行。

选择

SELECT count(1)
FROM tb2
LEFT JOIN tb1 ON tb1.nec = tb2.nec

结果大约是 180.000.000。

这只是一个示例,最终目标是使用其他日期过滤器/交叉点等进行更大的查询。

说明计划

来自 SQL Server 的执行计划:

配置、硬件……

@@innodb_buffer_pool_size: 2147483648
选择版本():5.7.17-0ubuntu0.16.04.1
Profiling of the query(CSV 文件)
Procedure Analyse()(XLS 文件)
my.cnf
系统:
VMware 虚拟平台
Intel(R) Xeon(R) CPU E5530 @ 2.40GHz
4GiB DIMM DRAM EDO
Ubuntu 16.04.2 LTS(Linux gt 4.4.0-66-generic x86_64)

【问题讨论】:

  • 慰问。我了解想要获得更便宜或开放的数据库,但这些天是 Postgresql,而不是 MySql。自 2004 年以来,MySql 一直没有跟上 Sql Server、Oracle 和 Postgresql 的进步。它甚至不再是一个现代数据库引擎:没有 CTE(递归或其他)、没有窗口函数、没有横向连接/应用、没有完全连接等等。
  • 可能是内存问题 用SELECT @@innodb_buffer_pool_size; 编辑您的问题并添加解释计划
  • 我敢打赌,如果您使用INNER JOIN 而不是LEFT JOIN,它会快得多。您是否需要计算tb2 中与tb1 中没有任何匹配的行?
  • 嗯...这不是默认的 128MB,但对于真正的数据库服务器来说,2GB 似乎仍然很小。理想情况下,您需要足够的空间来将所有表和索引一直保存在内存中(尽管不能这样做很常见)。相比之下,我现在正在使用的 Sql Server 的缓冲池等效值超过 16GB,而按照现代标准,这仍然很小。
  • @Mihai 发布@@innodb_buffer_pool_size 并说明计划

标签: mysql performance join


【解决方案1】:

这不是答案

我创建了 2 个带有随机数据的示例表(我知道它不一样),每个表有 500000 行并测试您的查询。这将需要 1.1 秒。所以我几乎可以肯定这是配置或硬件问题。所以我会使用更多的信息。你能把查询的输出贴出来吗

1) 选择版本();

2) 这个的输出

SET PROFILING=ON;

SELECT count(1)
FROM tb2
LEFT JOIN tb1 USING(nec);

SHOW PROFILE ALL;
SET PROFILING=OFF;

3) 你的 my.cnf

4) 关于硬件和操作系统的一些信息

你也可以检查这个查询。在我的服务器上只需要 500 毫秒

SELECT sum(IF(s IS NULL,1,s)) AS cnt
FROM tb2
LEFT JOIN 
  (SELECT DISTINCT nec, SUM(1) AS s FROM tb1 GROUP BY nec) tmp USING (nec) ;

【讨论】:

  • 我在第一篇文章中添加了所有信息。我试过你的最后一个查询,它只需要 800 毫秒!!!为什么???
  • 为什么不 :-) ,它比 50 秒好。我稍后会回答,我现在出去拜访某人。当我回来时,我会阅读你的帖子,抱歉耽搁了
  • 我的一个大错误:在 tb1 上,'nec' 字段可以为空。事实上,有很多行 'nec' = NULL。事实上,原始查询/SELECT 尝试丢弃 NULL 添加条件 tb1.nec IS NOT NULL,但这没有帮助。
  • 我也忘了执行一个查询 SELECT * FROM tb2 LEFT JOIN tb1 ON tb1.nec = tb2.nec PROCEDURE ANALYSE(); 你能帮我执行一下吗.谢谢
  • 添加了分析,但是选择 * 是一个永无止境的,我只对 id 和 nec 字段执行它。
【解决方案2】:

这里可能会发生很多事情,但考虑到您正在从一种数据库类型转移到另一种数据库类型的过程中,它很可能是一个服务器。考虑到这一点,可能仍然需要进行一些基本的服务器调整。例如,MySql 的缓冲池必须手动设置,否则它不会使用服务器中的大量内存。这样做了吗?

【讨论】:

  • 请向我们发布您对声明的解释,但看起来一切正常。您使用哪种引擎。
  • @BerndBuffen 解释已发布。引擎是 InnoDB。
  • 解释是否可能来自 SELECT count(1) FROM tb1 a LEFT JOIN tb2 b ON b.nec = a.nec 其中表名已更改
  • @BerndBuffen 是的,对不起!!更新了简单的解释(我正在尝试混合 SQL - 没有运气 - 并复制了错误的解释)
猜你喜欢
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-13
  • 2019-03-16
  • 2011-12-15
  • 1970-01-01
  • 2017-07-29
相关资源
最近更新 更多