我有一个相对简单的查询,但是它的性能确实很差。
我目前的速度约为0.800秒。每个查询。
有什么我需要更改以使其更快?
我已经尝试过索引索引列,这些列用于where语句和联接,但是没有用。
这是我正在使用的查询:
SELECT c.bloqueada, c.nomeF, c.confirmadoData
FROM encomendas_c_linhas el1
LEFT JOIN encomendas_c c ON c.lojaEncomenda=el1.lojaEncomenda
WHERE (el1.artigoE IN (342197) OR el1.artigoD IN (342197))
AND el1.desmembrado = 1
按照Bill Karwin的要求,下面是用于创建表格的查询:
表“ encomendas_c_linhas” https://pastebin.com/73WcsDnE
表“ encomendas_c”
答案 0 :(得分:2)
在您的解释中,我们看到它正在使用el1
访问type: ALL
表,这意味着它正在扫描整个表。 rows
字段显示已扫描的644,236行的估计值(大约)。
在el1
表的表定义中,您具有以下索引:
KEY `order_item_id_desmembrado` (`order_item_id`,`desmembrado`),
即使desmembrado
出现在索引中,该索引也无法帮助查询。您的查询搜索desmembrado = 1
,没有条件搜索order_item_id
。
想一想电话簿:我可以搜索姓氏为“ Smith”的人,而电话簿的顺序有助于我快速找到他们。但是,如果我搜索名字叫“ Sarah”的人,这本书就没有帮助。只有在索引的最左列上进行搜索时,它才有帮助。
因此,您需要使用desmembrado
作为最左列的索引。然后搜索desmembrado = 1
可能会使用索引来选择那些匹配的行。
ALTER TABLE encomendas_c_linhas ADD INDEX (desmembrado);
请注意,如果表中足够大的部分匹配,MySQL仍将跳过该索引。如果索引会匹配大部分行,则使用索引没有优势。根据我的经验,MySQL的优化器的判断是,如果条件匹配表行的20%以上,它将避免使用索引。
其他条件处于析取状态(OR
表达式的术语)。没有办法用单个索引来优化它们。同样,电话簿示例:用last name 'Smith' OR first name 'Sarah'
搜索人。姓氏查找已优化,但姓氏查找未优化。没问题,我们可以创建另一个索引,该索引首先列出名字,因此将优化名字查找。但通常,MySQL每个查询的每个表引用仅使用一个索引。因此,优化名字查找会破坏姓氏查找。
这是一种解决方法:将OR
条件重写为两个查询的UNION
,每个查询中包含一个词:
SELECT c.bloqueada, c.nomeF, c.confirmadoData
FROM encomendas_c_linhas el1
LEFT JOIN encomendas_c c ON c.lojaEncomenda=el1.lojaEncomenda
WHERE el1.artigoD IN ('342197')
AND el1.desmembrado = 1
UNION
SELECT c.bloqueada, c.nomeF, c.confirmadoData
FROM encomendas_c_linhas el1
LEFT JOIN encomendas_c c ON c.lojaEncomenda=el1.lojaEncomenda
WHERE el1.artigoE IN ('342197')
AND el1.desmembrado = 1;
确保每种情况都有一个索引。
ALTER TABLE encomendas_c_linhas
ADD INDEX des_artigoD (desmembrado, artigoD),
ADD INDEX des_artigoE (desmembrado, artigoE);
这些复合索引中的每一个都可以在各自的子查询中使用,因此它将在每种情况下优化对两列的查找。
还要注意,我将值放在引号中,例如IN ('342197')
,因为这些列是varchar,并且需要与varchar进行比较才能使用索引。将varchar列与整数值进行比较将成功进行匹配,但不会使用索引。
这是我为上一个查询测试的解释,它显示了使用了两个新索引,并且显示了ref: const,const
,这意味着索引的两列都用于查找。
+----+--------------+------------+------+-------------------------+---------------+---------+------------------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+------+-------------------------+---------------+---------+------------------------+------+-----------------------+
| 1 | PRIMARY | el1 | ref | des_artigoD,des_artigoE | des_artigoD | 41 | const,const | 1 | Using index condition |
| 1 | PRIMARY | c | ref | lojaEncomenda | lojaEncomenda | 61 | test.el1.lojaEncomenda | 2 | NULL |
| 2 | UNION | el1 | ref | des_artigoD,des_artigoE | des_artigoE | 41 | const,const | 1 | Using index condition |
| 2 | UNION | c | ref | lojaEncomenda | lojaEncomenda | 61 | test.el1.lojaEncomenda | 2 | NULL |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------+-------------------------+---------------+---------+------------------------+------+-----------------------+
但是我们可以做得更好。有时向索引中添加其他列会有所帮助,因为如果查询所需的所有列都包含在索引中,则它根本不必读取表行。这称为覆盖索引,如果您在EXPLAIN Extra字段中看到“正在使用索引”,则会显示该信息。
所以这是新的索引定义:
ALTER TABLE encomendas_c_linhas
ADD INDEX des_artigoD (desmembrado, artigoD, lojaEncomenda),
ADD INDEX des_artigoE (desmembrado, artigoE, lojaEncomenda);
第三列不用于查找,但是在连接到另一个表c
时使用。
您还可以通过创建@TheImpaler答案中建议的第二个索引来获得相同的覆盖索引效果:
create index ix2 on encomendas_c (lojaEncomenda, bloqueada, nomeF, confirmadoData);
我们看到EXPLAIN现在显示所有表引用的“使用索引”注释:
+----+--------------+------------+------+-------------------------+-------------+---------+------------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+------+-------------------------+-------------+---------+------------------------+------+--------------------------+
| 1 | PRIMARY | el1 | ref | des_artigoD,des_artigoE | des_artigoD | 41 | const,const | 1 | Using where; Using index |
| 1 | PRIMARY | c | ref | lojaEncomenda,ix2 | ix2 | 61 | test.el1.lojaEncomenda | 1 | Using index |
| 2 | UNION | el1 | ref | des_artigoD,des_artigoE | des_artigoE | 41 | const,const | 1 | Using where; Using index |
| 2 | UNION | c | ref | lojaEncomenda,ix2 | ix2 | 61 | test.el1.lojaEncomenda | 1 | Using index |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------+-------------------------+-------------+---------+------------------------+------+--------------------------+
答案 1 :(得分:1)
我将创建以下索引:
create index ix1 on encomendas_c_linhas (artigoE, artigoD, desmembrado);
create index ix2 on encomendas_c (lojaEncomenda, bloqueada, nomeF, confirmadoData);
第一个是关键的。第二个将进一步提高性能。