我对 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/