我有一个查询给我的问题,我不明白为什么MySQL的查询优化器的行为是这样的。这里是背景信息:为什么MySQL不能优化这个查询?
我有3个表格。两个比较小,一个比较大。
表1(非常小,727行):
CREATE TABLE
ipa
(
ipa_id
INT(11)NOT NULL AUTO_INCREMENT,
ipa_code
INT(11)DEFAULT NULL,
ipa_name
VARCHAR( 100)DEFAULT NULL,
payorcode
VARCHAR(2)DEFAULT NULL,
compid
INT(11)DEFAULT '2'
PRIMARY KEY(ipa_id
),
KEYipa_code
(ipa_code
)) ENGINE = MyISAM的
表2(短小,59455行):
CREATE TABLE
assign_ipa
(
assignid
INT(11 )NOT NULL AUTO_INCREMENT,
ipa_id
int(11)NOT NULL,
userid
int(11)NOT NUL L,
username
VARCHAR(20)DEFAULT NULL,
compid
INT(11)DEFAULT NULL,
PayorCode
CHAR(10)DEFAULT NULL
PRIMARY KEY(assignid
),
UNIQUE KEYassignid
(assignid
,ipa_id
),
KEYipa_id
(ipa_id
)
)ENGINE = MyISAM的
表3(大,24711730行):
CREATE TABLE
master_final
(
IPA
INT(11)DEFAULT NULL,
MbrCt
SMALLINT(6)DEFAULT '0',
PayorCode
VARCHAR(4)DEFAULT 'WC',
KEYidx_IPA
(IPA
)
)ENGINE = DEFAULT的MyISAM
现在进行查询。我正在做一个3路连接,使用前两个较小的表来实质上将大表的索引值之一子集。基本上,我得到一个用户的ID列表,SJOnes和查询大文件的这些ID。
mysql> explain
SELECT master_final。PayorCode,总和(master_final.Mbrct)AS MbrCt
FROM master_final
INNER JOIN IPA ON ipa.ipa_code = master_final.IPA
INNER JOIN assign_ipa ON ipa.ipa_id = assign_ipa.ipa_id
WHERE assign_ipa.username = 'SJones'
GROUP BY master_final.PayorCode,master_final.ipa \ G;
* ** * ** * ** * ** * 1排* ** * ** * ** * * * *
id:1
select_type:SIMPLE
表:master_final
类型:ALL
possible_keys:idx_IPA
键:NULL
key_len:NULL
REF:NULL
行:
额外:使用临时;使用文件排序
* ** * ** * ** * ** * 2.排* ** * ** * ** * ** *
id:1
select_type:SIMPLE
表:IPA
类型:REF
possible_keys:PRIMARY,ipa_code
键:ipa_code
key_len:5
REF:wc_test.master_final.IPA
行:1
额外:使用其中
* ** * ** * ** * ** * 3。行* ** * ** * ** * ** *
ID:1个
SELECT_TYPE:SIMPLE
表:assign_ipa
类型:REF
possible_keys: ipa_id
key:ipa_id
key_len:4
ref:wc_test.ipa .ipa_id
行:37
附加:(!好像是30分钟),用其中一套(0.00秒)
3行
这个查询需要永远。解释声明告诉我为什么,即使有一个完美的索引,它仍然在大桌面上进行全表扫描。它没有使用它。我不明白这一点。我可以查看查询并查看它只需要从大表中查询几个ID。如果我能做到,为什么MySQL的优化器无法做到这一点?
为了说明,这里是用 'SJones' 相关联的ID:
的MySQL>选择的用户名,从assign_ipa其中username = 'SJones' ipa_id;
+ ---------- + -------- +
|用户名| ipa_id |
+ ---------- + -------- +
| SJones | 688 |
| SJones | 689 |
+ ---------- + -------- +
2排在组(0.02秒)
现在,我可以重写查询替换ipa_id值用于where子句中的用户名。对我来说这相当于原始查询。 MySQL认为它不同。如果我这样做,优化器将利用大表上的索引。
的MySQL>解释
SELECT master_final.PayorCode,总和(master_final.Mbrct)AS MbrCt
FROM master_final
INNER JOIN IPA ON ipa.ipa_code = master_final.IPA
INNER JOIN ON ipa.ipa_id assign_ipa = assign_ipa.ipa_id
* WHERE中( '688', '689')assign_ipa.ipa_id *
GROUP BY master_final.PayorCode,master_final.ipa \ G;
* ** * ** * ** * ** * 1。行* ** * ** * ** * ** *
ID:1个
SELECT_TYPE:SIMPLE
表:IPA
类型:范围
possible_keys: PRIMARY,ipa_code
key:PRIMARY
key_len:4
ref:NULL
行数:2
额外:使用where;使用临时;使用文件排序
* ** * ** * ** * ** * 2.排* ** * ** * ** * ** *
id:1
select_type:SIMPLE
表:assign_ipa
类型:REF
possible_keys:ipa_id
键:ipa_id
key_len:4
REF:wc_test.ipa.ipa_id
行:37
额外:使用其中
* ** * ** * ** * ** * 3.行* ** * ** * ** * ** *
ID:1个
SELECT_TYPE:SIMPLE
表:master_final
类型:REF
possible_keys:idx_IPA
key:idx_IPA
key_len:5
REF:wc_test.ipa.ipa_code
行:
额外:使用哪里
3行中集(0.00秒)
我唯一改变的是一个WHERE子句甚至没有直接击中大牌。然而,优化器使用大表上的索引'idx_IPA',并且不再使用全表扫描。这样重写时的查询速度非常快。
好的,这是很多的背景。现在我的问题。为什么where子句对优化器有影响? Where子句将从较小的表中返回相同的结果集,但根据我使用哪一个结果,我得到的结果截然不同。显然,我想使用包含用户名的where子句,而不是试图将所有关联的ID传递给查询。正如所写,这是不可能的?
- 有人可以解释为什么会发生这种情况吗?
- 如何重写我的查询以避免全表扫描?
感谢您的支持。我知道这是一个很长的问题。
我读过一位MySQL开发人员(前段时间)的一篇文章,说优化器还在进行中 - 然后他们被Oracle吸收了。您是否尝试过使用“提示”或将“assign_ipa.username ='SJones'”移动到JOIN? – 2012-03-01 19:00:44