我无法理解以下解释:
第一个只关注PAZIENTE和ANALISI, 没关系,它正在使用索引IDX_NOME
explain
select
paziente3_.cognome as col_8_0_
from
Analisi analisi0_
inner join
Paziente paziente3_
on analisi0_.ID_PAZIENTE=paziente3_.ID_PAZIENTE
where
paziente3_.nome like 'MARCO%';
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE paziente3_ range PRIMARY,IDX_NOME IDX_NOME 123 1350 100 Using where; Using index
1 SIMPLE analisi0_ ref FK_ANALISI_PAZIENTE FK_ANALISI_PAZIENTE 4 gestelfolab.paziente3_.ID_PAZIENTE 1 100 Using index
如果在同一个查询中,我尝试检索SPECIE描述,不再使用索引IDX_NOME并且有一个完整的表扫描,
explain
select
specie5_.specie as col_5_0_,
paziente3_.cognome as col_8_0_
from
Analisi analisi0_
inner join
Paziente paziente3_
on analisi0_.ID_PAZIENTE=paziente3_.ID_PAZIENTE
inner join
Specie specie5_
on paziente3_.ID_SPECIE=specie5_.ID_SPECIE
where
paziente3_.nome like 'MARCO%';
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE specie5_ index PRIMARY SPECIE 137 1 100 Using index
1 SIMPLE paziente3_ ALL PRIMARY,IDX_NOME,FK_PAZIENTE_SPECIE 176184 10 Range checked for each record (index map: 0x19)
1 SIMPLE analisi0_ ref FK_ANALISI_PAZIENTE FK_ANALISI_PAZIENTE 4 gestelfolab.paziente3_.ID_PAZIENTE 1 100 Using index
是由于表定义中的错误吗?
CREATE TABLE SPECIE
(
ID_SPECIE TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
SPECIE VARCHAR(45) NOT NULL UNIQUE,
PRIMARY KEY (ID_SPECIE)
)
ENGINE=InnoDB;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
specie 0 PRIMARY 1 ID_SPECIE A 0 BTREE
specie 0 SPECIE 1 SPECIE A 0 BTREE
CREATE TABLE PAZIENTE
(
ID_PAZIENTE INT UNSIGNED NOT NULL AUTO_INCREMENT,
ID_PAZIENTE_LAB VARCHAR(20),
COGNOME VARCHAR(40),
NOME VARCHAR(40),
DATA_NASCITA DATE,
ID_SESSO TINYINT UNSIGNED NOT NULL,
RECAPITO VARCHAR(50),
CODICE_FISCALE VARCHAR(30),
ID_SPECIE TINYINT UNSIGNED NOT NULL,
PRIMARY KEY (ID_PAZIENTE),
INDEX IDX_DATA_NASCITA (DATA_NASCITA, ID_SESSO, ID_SPECIE),
INDEX IDX_COGNOME (COGNOME, NOME, ID_SESSO, ID_SPECIE),
INDEX IDX_NOME (NOME, COGNOME, ID_SESSO, ID_SPECIE),
CONSTRAINT FK_PAZIENTE_SPECIE FOREIGN KEY (ID_SPECIE) REFERENCES SPECIE(ID_SPECIE),
CONSTRAINT FK_PAZIENTE_SESSO FOREIGN KEY (ID_SESSO) REFERENCES SESSO(ID_SESSO)
)
ENGINE=InnoDB;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
paziente 0 PRIMARY 1 ID_PAZIENTE A 176176 BTREE
paziente 1 IDX_DATA_NASCITA 1 DATA_NASCITA A 15594 YES BTREE
paziente 1 IDX_DATA_NASCITA 2 ID_SESSO A 25007 BTREE
paziente 1 IDX_DATA_NASCITA 3 ID_SPECIE A 17922 BTREE
paziente 1 IDX_COGNOME 1 COGNOME A 62479 YES BTREE
paziente 1 IDX_COGNOME 2 NOME A 163074 YES BTREE
paziente 1 IDX_COGNOME 3 ID_SESSO A 170270 BTREE
paziente 1 IDX_COGNOME 4 ID_SPECIE A 154908 BTREE
paziente 1 IDX_NOME 1 NOME A 55289 YES BTREE
paziente 1 IDX_NOME 2 COGNOME A 166062 YES BTREE
paziente 1 IDX_NOME 3 ID_SESSO A 176184 BTREE
paziente 1 IDX_NOME 4 ID_SPECIE A 176184 BTREE
paziente 1 FK_PAZIENTE_SPECIE 1 ID_SPECIE A 1 BTREE
paziente 1 FK_PAZIENTE_SESSO 1 ID_SESSO A 1 BTREE
如果我强制使用新的IDX_NOME:
explain
select
specie5_.specie as col_5_0_,
paziente3_.cognome as col_8_0_
from
Analisi analisi0_
inner join
Paziente paziente3_ FORCE INDEX (IDX_NOME)
on analisi0_.ID_PAZIENTE=paziente3_.ID_PAZIENTE
inner join
Specie specie5_
on paziente3_.ID_SPECIE=specie5_.ID_SPECIE
where
paziente3_.nome like 'MARCO%'
;
结果如下:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE specie5_ index PRIMARY SPECIE 137 1 100 Using index
1 SIMPLE paziente3_ range IDX_NOME IDX_NOME 123 1350 100 Using where; Using index; Using join buffer (Block Nested Loop)
1 SIMPLE analisi0_ ref FK_ANALISI_PAZIENTE FK_ANALISI_PAZIENTE 4 gestelfolab.paziente3_.ID_PAZIENTE 1 100 Using index
也许我们可以说FULL TABLE SCAN 在这种情况下不是问题吗?
答案 0 :(得分:0)
当询问mysql为什么使用特定索引(或不是)时,请始终提供"在tablename"上显示索引的输出。为你的桌子。 mysql使用那里给出的信息来决定使用哪个索引。要理解为什么mysql使用索引,有助于使用mysql用来决定使用哪个索引的信息。
并且该信息可能已过期,因此您可能需要先执行ANALYZE TABLE ANALISI, PAZIENTE, SPECIE
并再次检查解释(它会锁定表格直到完成,以防万一您在生产服务器)。
Like
不是使用特定索引的强大指标,因为您可能会使用查询like '%Marco%
。如果发生这种情况,您现在也可以停止阅读,因为您的索引一般不会被使用(但您可能想要尝试全文索引)。
要执行join
和where
,您需要在ID_SPECIE
- 表格中提供有关NOME
和PATIENZE
的信息。不幸的是,你没有一个同时包含这两种信息的索引。
如果没有SHOW INDEX
- 数据,很难确定,但要获得结果,查找specie
信息条目可能是个好主意。 1}},所以你不必查看那张实际的桌子;另一方面,您可以在FK_PAZIENTE_SPECIE
- index中查找具有所需名称的条目。这将为您提供2个列表。现在您必须检查两个列表中的哪些条目。考虑一下如何执行此操作:获取列表1的条目(它包含主键),然后滚动列表2以查看主键是否也存在。如果您首先按主键对列表2进行排序,则可能会更快。
MySQL不能同时为同一个表使用两个索引(因为"使用索引"技术上意味着什么),但它当然可以做到与上面描述的类似的事情并仍然使用索引来获取所需的信息。这就是IDX_NOME
的含义:它结合了来自多个索引的信息(这里:Range checked for each record (index map: 0x19)
- 表中的第1,第4和第5个索引,如果我没有弄错的话,应该是{,{ {1}},SHOW INDEX FROM PAZIENTE
和PRIMARY
),每个都包含一些所需的信息。由于IDX_NOME
和FK_PAZIENTE_SPECIE
之间没有直接链接(它们通过IDX_NOME
间接链接),这可能会很快或很慢,具体取决于您的数据(因此,如果分析结果,它会有所帮助)信息是最新的,以帮助mysql决定做什么 - 在选择一个策略后,mysql不会改变策略,即使在执行过程中它被证明是一个糟糕的策略。)
因此,您的索引实际上已被使用,但不是以最快的方式使用。
该怎么办?如果你跟着到这里,你可能已经知道:"要执行FK_PAZIENTE_SPECIE
和PRIMARY
,您需要join
中的where
和ID_SPECIE
的相关信息}} - 表&#34。所以只需将其提供给mysql:使用两列创建索引。这取决于您的数据哪个订单更好,如果您想首先使用'%MARCO%NOME
ID_SPECIE`查询,因为索引无法使用,否则就会使用。
试试看,这应该让mysql现在使用新的索引。如果不是(也没有其他索引),这可能是一个很好的跟进问题,但请真的添加PATIENZE
- 信息。
您当然可以通过you should put
强制键,并检查它是否真的更快,或者mysql是否真的不使用它。
(但是,即使你搜索例如'%MARCO%'它也会尝试使用该索引,这实际上意味着根本没有索引,即使最好只使用show index
那么,你也必须添加这个,依此类推。所以请小心使用。)
尝试进行测试和比较可能值得尝试,如果现在... join
Paziente paziente3_ force index (idx_PAZIENTE_nome_specie) ...
(在添加另一个索引之前和FK_PAZIENTE_SPECIE
之前),就可以了。乍一看,我认为这应该已经使它更快,但也许mysql已经正确不使用索引。