[英]How to improve the performance of this query Sql in MySql?
我在 SQL 中有一个查询需要大约 15 秒才能返回结果,我需要提高性能,我已经工作了几个小时,但无法得到令人满意的结果。 MySql 5.6 表 lote:304053 行表 Prod_lista:41525 行时间结果:15 秒
SET @CODIGO_EMPRESA = 1;
SET @CODIGO_FILIAL = 1;
SET @PESQUISA = '%';
SELECT
B.CODIGO_PRODUTO,
C.DESCRICAO,
B.SALDO_DISPONIVEL,
B.SALDO_RESERVADO,
B.SALDO_INDISPONIVEL,
B.SALDO_TERCEIROS,
B.SALDO_ENTREGUE,
C.SITUACAO
FROM
(SELECT
A.CODIGO_EMPRESA,
A.CODIGO_FILIAL,
A.CODIGO_PRODUTO,
SUM(A.SALDO_DISPONIVEL) AS SALDO_DISPONIVEL,
SUM(A.SALDO_RESERVADO) AS SALDO_RESERVADO,
SUM(A.SALDO_INDISPONIVEL) AS SALDO_INDISPONIVEL,
SUM(A.SALDO_TERCEIROS) AS SALDO_TERCEIROS,
SUM(A.SALDO_ENTREGUE) AS SALDO_ENTREGUE
FROM
LOTE A
WHERE
A.CODIGO_EMPRESA = @CODIGO_EMPRESA
AND A.CODIGO_FILIAL = @CODIGO_FILIAL
AND IFNULL(A.ENCERRADO, 0) = 0
AND A.TIPO NOT IN (4 , 5)
GROUP BY A.CODIGO_PRODUTO
ORDER BY NULL) B
INNER JOIN
PROD_LISTA C ON B.CODIGO_EMPRESA = C.CODIGO_EMPRESA
AND B.CODIGO_FILIAL = C.CODIGO_FILIAL
AND B.CODIGO_PRODUTO = C.CODIGO
AND IFNULL(C.SITUACAO, 1) = 1
WHERE
(B.CODIGO_PRODUTO LIKE @PESQUISA
OR C.CODIGOFABRICA LIKE @PESQUISA
OR C.CODIGOBARRA_COMPLETO LIKE @PESQUISA
OR C.DESCRICAO LIKE @PESQUISA
OR EXISTS( SELECT
D.CODIGOPRODUTO
FROM
PROD_CODIGO_BARRA D
WHERE
D.CODIGO_EMPRESA = @CODIGO_EMPRESA
AND D.CODIGO_FILIAL = @CODIGO_FILIAL
AND B.CODIGO_PRODUTO = D.CODIGOPRODUTO
AND D.CODIGOBARRA_COMPLETO LIKE @PESQUISA))
LIMIT 0 , 100
批处理表的结构
CREATE TABLE `lote` (
`CODIGO_EMPRESA` int(3) unsigned NOT NULL,
`CODIGO_FILIAL` int(4) unsigned NOT NULL,
`CODIGO_LOTE` bigint(20) NOT NULL,
`CODIGO_LOTE_PAI` bigint(20) DEFAULT NULL,
`NUMERO_LOTE` varchar(15) DEFAULT NULL,
`TIPO` int(2) DEFAULT NULL ,
`DATAHORA` datetime DEFAULT NULL,
`CODIGO_DOCUMENTO` bigint(20) DEFAULT NULL,
`CODIGO_ITEM` int(5) DEFAULT NULL,
`CUSTO` decimal(21,10) DEFAULT '0.0000000000',
`CODIGO_PRODUTO` varchar(25) DEFAULT NULL,
`DESTINO_INICIAL` int(1) DEFAULT NULL,
`SALDO_INICIAL` decimal(15,4) DEFAULT '0.0000',
`SALDO_DISPONIVEL` decimal(15,4) DEFAULT '0.0000',
`SALDO_INDISPONIVEL` decimal(15,4) DEFAULT '0.0000',
`SALDO_TERCEIROS` decimal(15,4) DEFAULT '0.0000',
`SALDO_RESERVADO` decimal(15,4) DEFAULT '0.0000',
`SALDO_ENTREGUE` decimal(15,4) DEFAULT '0.0000',
`VENCIMENTO` date DEFAULT NULL,
`ENCERRADO` int(1) DEFAULT '0',
`CODIGO_CONTAGEM` bigint(11) unsigned DEFAULT NULL,
PRIMARY KEY (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_LOTE`),
KEY `IDX_CODIGO_LOTE` (`CODIGO_LOTE`),
KEY `IDX_CODIGO_PRODUTO` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_PRODUTO`),
KEY `IDX_CONSULTA_PDV` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_PRODUTO`,`ENCERRADO`,`TIPO`),
KEY `IDX_CONTAGEM_ESTOQUE` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_PRODUTO`,`TIPO`,`ENCERRADO`),
KEY `IDX_CUSTO` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CUSTO`),
KEY `IDX_DOCUMENTO_ITEM` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_DOCUMENTO`,`CODIGO_ITEM`),
KEY `IDX_EMPRESA_FILIAL` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`),
KEY `IDX_ESTOQUE` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`TIPO`,`ENCERRADO`),
KEY `IDX_FILTRO` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_LOTE`,`DATAHORA`),
KEY `IDX_LOTE_COMP` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_PRODUTO`,`DATAHORA`),
KEY `IDX_TIPO` (`TIPO`),
KEY `IDX_TIPO_CODIGO` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`TIPO`,`CODIGO_PRODUTO`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
如何改进 SQL 以获得更快的结果?
OR
是性能杀手; 尽量避免它。
B.CODIGO_PRODUTO LIKE "%"
等价于TRUE
,但优化器没有看到。 动态构造查询而不是使用@variables 并选择消除子句的值会好得多。
同样重要的是,当没有前导通配符时,优化器可能能够使用索引:
x LIKE 'A%' -- possibly uses index x LIKE '%' -- cannot use index x LIKE '%B' -- cannot use index x LIKE '@foo' -- cannot use index
int(4)
- (4)
无关紧要。 所有INTs
都是相同的 4 字节数据类型。 对于较小的数据类型,请参阅SMALLINT
和类似的。
不要盲目使用NULL
(您的大多数列都是NULLable
); 为可选/未知/等值保留NULL
。
IFNULL(A.ENCERRADO, 0) = 0
-- 如果可以将其安排为具有 2 个值(0 和 1),则可以简化此表达式并避免使用函数。 函数使表达式不是 'sargable'。 完成后,下面建议的索引可能会有用。
当您有INDEX(a,b,c)
,就不需要也有INDEX(a,b)
。 例如: IDX_EMPRESA_FILIAL
可以删除。
这些索引可能有帮助:
D: (CODIGOPRODUTO, CODIGO_FILIAL, CODIGO_EMPRESA, CODIGOBARRA_COMPLETO) A: (ENCERRADO, CODIGO_FILIAL, TIPO, CODIGO_EMPRESA)
可能还有更多建议。 应用以上大部分内容,然后回来获取更多建议。 (并提供其他SHOW CREATE TABLEs
。)
相关子查询,如您的 EXISTS 查询,如果它们与来自外部查询的大量结果相关联,则可能代价高昂。 我建议将您的 EXISTS 条件转换为这样的:
OR B.CODIGO_PRODUTO IN (
SELECT D.CODIGOPRODUTO
FROM PROD_CODIGO_BARRA AS D
WHERE D.CODIGO_EMPRESA = @CODIGO_EMPRESA
AND D.CODIGO_FILIAL = @CODIGO_FILIAL
AND D.CODIGOBARRA_COMPLETO LIKE @PESQUISA
)
对于您的相关版本,子查询最终会针对来自主 FROM 的每一行进行单独评估。 但是对于这个不相关的版本,子查询只被评估一次,它的结果集用于检查来自主 FROM 的行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.