mysql:为啥左连接不使用索引?

Posted

技术标签:

【中文标题】mysql:为啥左连接不使用索引?【英文标题】:mysql: why does left join not use an index?mysql:为什么左连接不使用索引? 【发布时间】:2013-09-10 16:48:13 【问题描述】:

我遇到了一个奇怪的 mysql 查询性能问题。

SELECT
`pricemaster_products`.*,
`products`.*
FROM `pricemaster_products`
LEFT JOIN `products`
ON `pricemaster_products`.`ean` = `products`.`products_ean`

我明确地想使用左连接。但是查询花费的时间比它应该的要长。

我尝试将联接更改为 INNER JOIN。现在查询确实很快,但是结果不是我需要的。

我用explain,得出以下结论:

如果我使用“LEFT JOIN”,那么查询的解释会导致...

type: "ALL"
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 90.000 / 50.000 (the full number of the corresponding table)

...对于两个表。

如果我使用“INNER JOIN”,则 EXPLAIN 给出:

对于表“产品”:

Same result as above.

对于表“pricemaster_products”:

type: "ref"
possible_keys: "ean"
key: ean
key_len: 767
ref: func
rows: 1
extra: using where

两个表都在相关列上设置了索引。我能想到的 LEFT JOIN 这么慢的唯一可能原因是根本不使用索引。但为什么不呢?

表结构如下:

CREATE TABLE IF NOT EXISTS `pricemaster_products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `provider` varchar(255) CHARACTER SET utf8 NOT NULL,
  `ean` varchar(255) CHARACTER SET utf8 NOT NULL,
  `title` varchar(255) CHARACTER SET utf8 NOT NULL,
  `gnp` double DEFAULT NULL,
  `vat` int(11) DEFAULT NULL,
  `cheapest_price_with_shipping` double DEFAULT NULL,
  `last_cheapest_price_update` int(11) DEFAULT NULL,
  `active` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `ean` (`ean`),
  KEY `title` (`title`),
  KEY `gnp` (`gnp`),
  KEY `vat` (`vat`),
  KEY `provider` (`provider`),
  KEY `cheapest_price_with_shipping` (`cheapest_price_with_shipping`),
  KEY `last_cheapest_price_update` (`last_cheapest_price_update`),
  KEY `active` (`active`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=58436 ;

CREATE TABLE IF NOT EXISTS `products` (
  `products_id` int(11) NOT NULL AUTO_INCREMENT,
  `products_ean` varchar(128) DEFAULT NULL,
  `products_status` tinyint(1) NOT NULL DEFAULT '1',
  [a lot more of fields with no connection to the query in question]
  PRIMARY KEY (`products_id`),
  KEY `products_status` (`products_status`),
  KEY `products_ean` (`products_ean`),
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=105518 ;

【问题讨论】:

你有哪个版本的 MySQL? MySQL 版本为 5.1.70 @juergend:不,它是“给我左表中的所有数据以及右表中可用的所有数据”。你正在考虑一个完整的外部连接 您在这里处理多少条记录?内连接总是比左连接快,尤其是在处理大量记录时。 好吧,ean 是一个表是varchar(255)CHARACTER SET utf8,另一个是varchar(128)latin1。这可能是相关的。 【参考方案1】:

连接的两个相关字段的类型不完全相同(varchar(255) 与 CHARACTER SET utf8 和 varchar(128) 与 latin1)。我确实将两者都设置为相同的长度和字符集,现在使用 LEFT JOIN 的查询按预期工作。

【讨论】:

天哪**ing sht。我完全忽略了这件事。谢谢。 +1 非常感谢,这帮助我找到了我的一个查询的问题,其中一个表创建不正确(使用错误的字符集)正在产生问题。 +1 非常感谢,我也遇到了同样的问题,这让我绝对是香蕉 这是一个很好的答案!非常感谢! 知道为什么在这种情况下 INNER JOIN 能够使用索引而不是 LEFT JOIN 吗?

以上是关于mysql:为啥左连接不使用索引?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 索引优化与子查询与左连接

为啥 mySQL 查询,左连接“明显”比我的内连接快

具有三个未索引联合表和左连接的 MySQL 查询使数据库负担过重

MySQL中的索引左连接右连接joinsql执行顺序

MariaDB / MySQL:存在左连接时忽略索引提示

ORACLE左连接索引失效,怎么解决