此查询:
explain
SELECT `Lineitem`.`id`, `Donation`.`id`, `Donation`.`order_line_id`
FROM `order_line` AS `Lineitem`
LEFT JOIN `donations` AS `Donation`
ON (`Donation`.`order_line_id` = `Lineitem`.`id`)
WHERE `Lineitem`.`session_id` = '1'
正确使用{EXPLES输出中显示的Donation.order_line_id
和Lineitem.id
索引:
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE Lineitem ref session_id session_id 97 const 1 Using where; Using index 1 SIMPLE Donation ref order_line_id order_line_id 4 Lineitem.id 2 Using index
但是,这个查询只包含另一个字段:
explain
SELECT `Lineitem`.`id`, `Donation`.`id`, `Donation`.`npo_id`,
`Donation`.`order_line_id`
FROM `order_line` AS `Lineitem`
LEFT JOIN `donations` AS `Donation`
ON (`Donation`.`order_line_id` = `Lineitem`.`id`)
WHERE `Lineitem`.`session_id` = '1'
显示Donation
表不使用索引:
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE Lineitem ref session_id session_id 97 const 1 Using where; Using index 1 SIMPLE Donation ALL order_line_id NULL NULL NULL 3
表中的所有_id
字段都已编制索引,但我无法弄清楚如何将此字段添加到所选字段列表中会导致索引被删除。
根据James C的要求,以下是表格定义:
CREATE TABLE `donations` (
`id` int(10) unsigned NOT NULL auto_increment,
`npo_id` int(10) unsigned NOT NULL,
`order_line_detail_id` int(10) unsigned NOT NULL default '0',
`order_line_id` int(10) unsigned NOT NULL default '0',
`created` datetime default NULL,
`modified` datetime default NULL,
PRIMARY KEY (`id`),
KEY `npo_id` (`npo_id`),
KEY `order_line_id` (`order_line_id`),
KEY `order_line_detail_id` (`order_line_detail_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
CREATE TABLE `order_line` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`order_id` bigint(20) NOT NULL,
`npo_id` bigint(20) NOT NULL default '0',
`session_id` varchar(32) collate utf8_unicode_ci default NULL,
`created` datetime default NULL,
PRIMARY KEY (`id`),
KEY `order_id` (`order_id`),
KEY `npo_id` (`npo_id`),
KEY `session_id` (`session_id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8
我也做了一些关于基数的阅读,看起来Donations.npo_id
和Donations.order_line_id
的基数都是2.希望这表明有用的东西?
我认为USE INDEX
可能会解决问题,但我正在使用ORM,这使得这有点棘手,我不明白为什么它不能抓住正确的索引JOIN专门命名索引字段?!?
感谢您的智慧!
答案 0 :(得分:3)
第一个解释最后有“使用索引”。这意味着它能够找到行和通过查看索引而不必获取/分析任何行数据来返回查询结果。
在第二个查询中添加一个可能未编入索引的行。这意味着MySQL必须查看表的数据。我不确定为什么优化器选择进行表扫描,但我认为如果表格相当小,它可能更容易阅读所有内容而不是尝试挑选各行的详细信息。
编辑:我认为添加以下索引会进一步改善,并且只允许所有连接使用索引:
ALTER TABLE order_line ADD INDEX(session_id, id);
ALTER TABLE donations ADD INDEX(order_line_id, npo_id, id)
这将允许order_line
使用session_id
查找行,然后返回id
并允许donations
加入order_line_id
,然后返回另外两列。
查看auto_increment
值,我可以假设其中没有太多数据。值得注意的是,表格中的数据量会对查询计划产生影响,最好将一些样本数据放在那里进行测试。有关详细信息,请查看此博客文章,我花了一些时间回顾:http://webmonkeyuk.wordpress.com/2010/09/27/what-makes-a-good-mysql-index-part-2-cardinality/