mysql - 不知道为什么连接查询返回结果集的时间比我预期的要长,并且执行需要很长时间

标签 mysql database performance join

我对 mysql 连接的了解陷入了僵局,并且我尝试执行的查询花费了太长的时间...虽然我自己学习 mysql 的时间很短,但我已经把花时间阅读索引和连接的机制,进行了许多谷歌搜索并尝试了几种不同的查询格式。无济于事,我需要帮助。

首先,我要说的是,我的数据库目前正在针对选择查询的速度进行优化。我知道我有一些太多的索引...我学习mysql的理论是创建一些太多的索引并检查mysql优化器为我的目的选择的内容(通过使用解释确定),然后确定为什么它选择了所述索引.

无论如何,我有四个表:table1、table2、table3、table4...

table1.ID1为主键,table1中的其他数据可能会被分成table2中的多个内容。 table2.ID1 标识 table1 中基于内容形式 table1 构建的每个条目 table2.ID2 是 table2 的主键 table3.ID2 标识 table3 中基于 table2 内容构建的每个条目 table3.ID3是table3的主键 table4.ID3 标识 table4 中基于 table3 内容构建的每个条目

并非表 1 中的每个条目在表 2 中都有对应的数据,表 2 到表 3、表 3 到表 4 也同样如此。

我需要做的是检索出现在日期范围内的 ID2 的不同值,并且仅当 table2 内容最终出现在 table4 中时才检索。我面临的挑战是只有 table1 有日期列,并且我只需要也出现在 table4 中的条目。

以下查询大约需要 2 分钟。

select table2.ID2 from table1 
left join table2 on
table1.ID1 = table2.ID1
left join table3 on
table3.ID2 = table2.ID2 
left join table4 on
table4.ID3 = table3.ID3
where table1.Date between "2012-03-11" and "2012-03-18

通过对上述查询使用解释,我看不出为什么需要这么长时间。

+----+-------------+--------------+-------+----------------------+----------+---------+------------------------------+-------+--------------------------+
| id | select_type | table        | type  | possible_keys        | key      | key_len | ref                          | rows  | Extra                    |
+----+-------------+--------------+-------+----------------------+----------+---------+------------------------------+-------+--------------------------+
|  1 | SIMPLE      | table1       | range | ...                  | Datekey  | 9       | NULL                         | 17528 | Using where; Using index |
|  1 | SIMPLE      | table2       | ref   | ...                  | ID1key   | 8       | mydata.table1.POSTID         |     1 |                          |
|  1 | SIMPLE      | table3       | ref   | ...                  | ID2key   | 8       | mydata.table2.SrcID          |    20 |                          |
|  1 | SIMPLE      | table4       | ref   | ...                  | ID3key   | 8       | mydata.table3.ParsedID       |    10 | Using index              |
+----+-------------+--------------+-------+----------------------+----------+---------+------------------------------+-------+--------------------------+

我已将可能的键的名称替换为“...”,因为它并不那么重要。无论如何,都会选择一个键。

此外,查询结果集中的行数远多于解释结果集中据称匹配的 17528 行。怎么可能更多?

我做错了什么?我也尝试过内部连接,但没有成功。我解释查询的方式是 4 路维恩图,具有重叠条件的行数很少,并通过日期范围上的索引进一步优化。

如果我添加“distinct(table2.ID2)”,我至少会得到我想要的结果集,但是为什么我得到的结果集比我预期的要长得多,为什么要花这么长时间?

抱歉,如果我的问题的任何部分含糊不清,我很乐意根据需要进行澄清。

谢谢, 布赖恩

编辑:

所有索引都引用 BIGINT 列,因为我预计我的数据库会变得相当大,并且需要相当多的唯一行标识符...也许 bigint 是矫枉过正,减少该列和/或索引的大小会加快速度事情进一步发展。

这是我的最终解决方案,基于下面接受的答案:

select ID2 from table2
where exists
    (select 1 from table1 r
    where table1.Date between "2012-03-11" and "2012-03-18" and table2.ID1 = table1.ID1
    )
and exists
    (select 1 from table3
    where exists 
        (select 1 from table4 where table4.ID3 = table3.ID3) 
    )

此外,我意识到我缺少一个多字段索引,关联 table2.ID1 和 table2.ID2...添加此索引后,此语句在大约 11 秒内返回,并返回大约 20,000 行。

考虑到每个表中的行数,我认为这是合理的 表1:~480,000 表2:~480,000 表3:~6,000,000 表4:~60,000,000

这听起来有效吗?在确认这是我应该期望的最佳表现后,我会接受答案。我正在 Xeon 3GHz 系统上运行,具有 3gb mem、ubuntu 12.04、mysql 5.5.24

最佳答案

您的表之间很可能有多个匹配项。假设 table1 匹配 table2 中的 5 行和 table3 中的 10 行。然后您最终会在输出中得到 50 行。

因此,解决这个问题,您需要将联接限制为每个表一行。

一种方法是使用 in 子句。如果您使用联接进行过滤,则可以使用 where 子句:

where table2.id1 in (select table1.id1 from table1)

“in”可以防止重复。

另一种选择是通过执行联接来预先聚合联接中的查询。

从优化的角度来看,Mysql 似乎更喜欢使用稍微不同的 where 子句结构:

where exists (select 1 from table1 where table1.id = table2.id)

关于mysql - 不知道为什么连接查询返回结果集的时间比我预期的要长,并且执行需要很长时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11706166/

相关文章:

php - 使用 XAMPP 连接到外部数据库的 MySQL

C:Memcpy vs Shifting:哪个更有效率?

java - LibGDX:循环时使用 SpriteBatches

来自 mysql_next_result() 的 MySQL 5.3 未处理错误

mysql - 如何计算日期来制作事件列表?

SQL:按 1 到 10 的范围排列数字

android - 关于 Room DB 中的关系,我应该采用哪种方法?

mysql - 在多行上使用 LEFT JOIN 简化我的 SQL

MySQL 为新的 "prepare"从服务器断开连接

mysql - SQLSTATE[23000] : Integrity constraint violation: 1048 Column 'name' cannot be null (SQL: insert using Laravel 5. 1.*