下面是4个表的表结构:
日历:
CREATE TABLE `calender` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`HospitalID` int(11) NOT NULL,
`ColorCode` int(11) DEFAULT NULL,
`RecurrID` int(11) NOT NULL,
`IsActive` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`ID`),
UNIQUE KEY `ID_UNIQUE` (`ID`),
KEY `idxHospital` (`ID`,`StaffID`,`HospitalID`,`ColorCode`,`RecurrID`,`IsActive`)
) ENGINE=InnoDB AUTO_INCREMENT=4638 DEFAULT CHARSET=latin1;
CalendarAttendee:
CREATE TABLE `calenderattendee` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`CalenderID` int(11) NOT NULL,
`StaffID` int(11) NOT NULL,
`IsActive` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`ID`),
KEY `idxCalStaffID` (`StaffID`,`CalenderID`)
) ENGINE=InnoDB AUTO_INCREMENT=20436 DEFAULT CHARSET=latin1;
CallPlanStaff:
CREATE TABLE `callplanstaff` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Staffname` varchar(45) NOT NULL,
`IsActive` tinyint(4) NOT NULL DEFAULT '1',
PRIMARY KEY (`ID`),
UNIQUE KEY `ID_UNIQUE` (`ID`),
KEY `idx_IsActive` (`Staffname`,`IsActive`),
KEY `idx_staffName` (`Staffname`,`ID`) USING BTREE KEY_BLOCK_SIZE=100
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1;
用户:
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(255) NOT NULL DEFAULT '',
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `index_users_on_email` (`email`),
UNIQUE KEY `index_users_on_name` (`name`),
KEY `idx_email` (`email`) USING BTREE KEY_BLOCK_SIZE=100
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
我要做的是使用以下查询获取calender.ID和Users.name:
SELECT a.ID, h.name
FROM `stjude`.`calender` a
left join calenderattendee e on a.ID = e.calenderID
left join callplanstaff f on e.StaffID = f.ID
left join users h on f.Staffname = h.email
这些表之间的关系是:
我花了大约4秒来获取13000条记录,我打赌它可能会更快。
当我查看查询的表格解释时,结果如下:
为什么MYSQL没有在callplanstaff表和users表上使用索引?
另外,在我的情况下,我应该使用多索引而不是多列索引吗?
是否有我缺少的索引,所以我的查询很慢?
=============================================== ========================
更新:
由于zedfoxus和spencer7593建议更改idxCalStaffID的排序和idx_staffname的排序,下面是执行计划:
获取需要0.063秒,所需的时间要少得多,索引的排序如何影响获取时间..?
答案 0 :(得分:3)
您误解了EXPLAIN报告。
type: index
不是一件好事。这意味着它正在做一个"索引扫描"它检查索引的每个元素。它几乎和桌面扫描一样糟糕。请注意列rows: 4562
和rows: 13451
。这是它将为每个表检查的索引元素的估计数量。Using join buffer
不是一件好事。当优化器无法使用索引进行连接时,优化器就可以作为安慰。 type: eqref
是一件好事。这意味着它使用PRIMARY KEY索引或UNIQUE KEY索引来准确查找一行。请注意列rows: 1
。因此,至少对于前一个连接中的每一行,它只进行一次索引查找。
您应该按顺序在calenderattendee上为列(CalenderId,StaffId)创建索引(@ spencer7593在我撰写帖子时发布了此建议)。
LEFT [OUTER] JOIN
,可以防止MySQL优化表连接的顺序。由于您的查询提取h.name
,我推断您确实只想要日历事件有与会者的结果,并且与会者具有相应的用户记录。您没有使用INNER JOIN
。这里是使用新索引的EXPLAIN,并且连接更改为INNER JOIN
(尽管我的行数没有意义,因为我没有创建测试数据):
+----+-------------+-------+------------+--------+--------------------------------+----------------------+---------+----------------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+--------------------------------+----------------------+---------+----------------+------+----------+-----------------------+
| 1 | SIMPLE | a | NULL | index | PRIMARY,ID_UNIQUE,idxHospital | ID_UNIQUE | 4 | NULL | 1 | 100.00 | Using index |
| 1 | SIMPLE | e | NULL | ref | idxCalStaffID,CalenderID | CalenderID | 4 | test.a.ID | 1 | 100.00 | Using index |
| 1 | SIMPLE | f | NULL | eq_ref | PRIMARY,ID_UNIQUE | PRIMARY | 4 | test.e.StaffID | 1 | 100.00 | NULL |
| 1 | SIMPLE | h | NULL | eq_ref | index_users_on_email,idx_email | index_users_on_email | 767 | func | 1 | 100.00 | Using index condition |
+----+-------------+-------+------------+--------+--------------------------------+----------------------+---------+----------------+------+----------+-----------------------+
calenderattendee表的type: index
已更改为type: ref
,这意味着针对非唯一索引进行索引查找。关于Using join buffer
的说明已经消失。
那应该会更好。
索引的排序如何影响获取时间..?
想一下电话簿,先按姓氏排序,然后按名字排序。这有助于您快速查找姓氏。但它并没有帮助你以名字查找人。
索引中列的位置很重要!
您可能会喜欢我的演示如何设计索引,真的。
答案 1 :(得分:1)
问:我是否缺少任何索引,因此我的查询速度很慢?
A:是的。缺少calendarattendee
的合适索引。
我们可能希望calenderattendee
上的索引为calendarid
作为前导列,例如:
... ON calenderattendee (calendaid, staffid)
答案 2 :(得分:1)
这似乎是内部联接可能比左联接更好的选择。
SELECT a.ID, h.name
FROM `stjude`.`calender` a
INNER JOIN calenderattendee e on a.ID = e.calenderID
INNER JOIN callplanstaff f on e.StaffID = f.ID
INNER JOIN users h on f.Staffname = h.email
然后让我们进入索引。日历表有
PRIMARY KEY (`ID`),
UNIQUE KEY `ID_UNIQUE` (`ID`),
第二个,ID_UNIQUE是多余的。主键是唯一索引。索引太多会降低插入/更新/删除操作的速度。
然后users表有
UNIQUE KEY `index_users_on_email` (`email`),
UNIQUE KEY `index_users_on_name` (`name`),
KEY `idx_email` (`email`) USING BTREE KEY_BLOCK_SIZE=100
这里的idx_email列是多余的。除此之外,通过调整索引没有太多事情要做。您的解释显示正在每个表和表上使用索引。
为什么MYSQL在callplanstaff表和users表上没有使用索引?
你的解释表明确实如此。它在这些表上使用主键和index_users_on_email索引。
另外,在我的情况下,我应该使用多索引而不是多列 索引?
根据经验,mysql每个表只使用一个索引。因此,多列索引是一种方法,而不是具有多个索引。
是否有我失踪的索引,所以我的查询很慢?
正如我在评论中提到的那样,你正在获取(并且可能显示)13,000条记录。这可能是你的瓶颈所在。