如何在mysql上优化select sum()?
我有一个SQL,运行大约需要2,5秒如何在mysql上优化select sum()?,mysql,sql,select,optimization,Mysql,Sql,Select,Optimization,我有一个SQL,运行大约需要2,5秒 select SUM(valorlanca0_.VALOR_PREVISTO) as col_0_0_ from CF_VALOR_LANCADO_DETALHADO valorlanca0_ inner join CF_VALOR_LANCADO valorlanca1_ on valorlanca0_.ID_VALOR_LANCADO=valorlanca1_.ID_VALOR_LANCADO inner join CF_LANCAMENTO la
select SUM(valorlanca0_.VALOR_PREVISTO) as col_0_0_
from CF_VALOR_LANCADO_DETALHADO valorlanca0_
inner join CF_VALOR_LANCADO valorlanca1_ on valorlanca0_.ID_VALOR_LANCADO=valorlanca1_.ID_VALOR_LANCADO
inner join CF_LANCAMENTO lancamento2_ on valorlanca1_.ID_LANCAMENTO=lancamento2_.ID_LANCAMENTO
inner join CF_ADMINISTRACAO administra12_ on lancamento2_.ID_ADMINISTRACAO=administra12_.ID_ADMINISTRACAO
inner join CF_EMPRESA empresa13_ on lancamento2_.ID_EMPRESA=empresa13_.ID_EMPRESA
inner join CF_USUARIO usuario14_ on lancamento2_.ID_USUARIO_CRIOU=usuario14_.ID_USUARIO
left outer join CF_FORMA_PAGAMENTO formapagam9_ on valorlanca1_.ID_FORMA_PAGAMENTO=formapagam9_.ID_FORMA_PAGAMENTO
inner join CF_CONTA conta10_ on valorlanca1_.ID_CONTA=conta10_.ID_CONTA
left outer join CF_FATURA fatura11_ on valorlanca1_.ID_FATURA=fatura11_.ID_FATURA
left outer join CF_CATEGORIA categoria3_ on valorlanca0_.ID_CATEGORIA=categoria3_.ID_CATEGORIA
left outer join CF_CENTRO_CUSTO centrocust4_ on valorlanca0_.ID_CENTRO_CUSTO=centrocust4_.ID_CENTRO_CUSTO
left outer join CF_FAV_FONTE_PAGADORA favfontepa5_ on valorlanca0_.ID_FAV_FONTE_PAGADORA=favfontepa5_.ID_FAV_FONTE_PAGADORA
left outer join CF_CONTA_CONTABIL contaconta6_ on valorlanca0_.ID_CONTA_CONTABIL=contaconta6_.ID_CONTA_CONTABIL
left outer join CF_CONTATO contato7_ on valorlanca0_.ID_CONTATO=contato7_.ID_CONTATO
left outer join CF_MARCA marca8_ on valorlanca0_.ID_MARCA=marca8_.ID_MARCA
where administra12_.ID_ADMINISTRACAO=406 and lancamento2_.TIPO_CONTA=2 and (conta10_.ID_CONTA in (2060, 404, 405, 4291, 406, 410, 4292, 403, 4355, 402, 407)) and conta10_.TIPO<>9 and lancamento2_.TIPO_TRANSACAO=10
and (valorlanca1_.SITUACAO in (1)) and ((valorlanca1_.DATA_PREVISTA<='2015-07-22' and valorlanca1_.SITUACAO=1 or valorlanca1_.DATA_BAIXA<='2015-07-22' and valorlanca1_.SITUACAO=3)
and conta10_.TIPO<>2 or fatura11_.DATA_VENCIMENTO<='2015-07-22' and conta10_.TIPO=2 and valorlanca1_.SITUACAO=1 or valorlanca1_.DATA_BAIXA<='2015-07-22' and conta10_.TIPO=2 and valorlanca1_.SITUACAO=3)
and ((empresa13_.ID_EMPRESA in (422, 3643)) and usuario14_.ID_USUARIO=574 or empresa13_.ID_EMPRESA in (422, 3643))
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
最大的表格是CF_VALOR_LANCADO(8.55亿条记录)和CF_VALOR_LANCADO_DETALHADO(8.60亿条记录)
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
我能做些什么来优化我的选择?那是一个地狱般的查询:)
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
您可以从删除您未使用的表开始,然后执行以下操作:
select SUM(valorlanca0_.VALOR_PREVISTO) as col_0_0_
from CF_VALOR_LANCADO_DETALHADO valorlanca0_
inner join CF_VALOR_LANCADO valorlanca1_ on valorlanca0_.ID_VALOR_LANCADO=valorlanca1_.ID_VALOR_LANCADO
inner join CF_LANCAMENTO lancamento2_ on valorlanca1_.ID_LANCAMENTO=lancamento2_.ID_LANCAMENTO
inner join CF_ADMINISTRACAO administra12_ on lancamento2_.ID_ADMINISTRACAO=administra12_.ID_ADMINISTRACAO
inner join CF_EMPRESA empresa13_ on lancamento2_.ID_EMPRESA=empresa13_.ID_EMPRESA
inner join CF_USUARIO usuario14_ on lancamento2_.ID_USUARIO_CRIOU=usuario14_.ID_USUARIO
inner join CF_CONTA conta10_ on valorlanca1_.ID_CONTA=conta10_.ID_CONTA
left outer join CF_FATURA fatura11_ on valorlanca1_.ID_FATURA=fatura11_.ID_FATURA
where administra12_.ID_ADMINISTRACAO=406
and lancamento2_.TIPO_CONTA=2
and (conta10_.ID_CONTA in (2060, 404, 405, 4291, 406, 410, 4292, 403, 4355, 402, 407))
and conta10_.TIPO<>9
and lancamento2_.TIPO_TRANSACAO=10
and (valorlanca1_.SITUACAO in (1))
and ((valorlanca1_.DATA_PREVISTA<='2015-07-22' and valorlanca1_.SITUACAO=1 or valorlanca1_.DATA_BAIXA<='2015-07-22' and valorlanca1_.SITUACAO=3) and conta10_.TIPO<>2
or fatura11_.DATA_VENCIMENTO<='2015-07-22' and conta10_.TIPO=2 and valorlanca1_.SITUACAO=1
or valorlanca1_.DATA_BAIXA<='2015-07-22' and conta10_.TIPO=2 and valorlanca1_.SITUACAO=3
)
and ((empresa13_.ID_EMPRESA in (422, 3643)) and usuario14_.ID_USUARIO=574 or empresa13_.ID_EMPRESA in (422, 3643))
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
相当于
and empresa13_.ID_EMPRESA in (422, 3643)
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
您也可以尝试这个更改(95%确定它们是等效的)-不会有嵌套的“或”,这在我的经验中有时有助于提高性能
and (
(valorlanca1_.DATA_PREVISTA<='2015-07-22' and valorlanca1_.SITUACAO=1
or valorlanca1_.DATA_BAIXA<='2015-07-22' and valorlanca1_.SITUACAO=3
) and conta10_.TIPO<>2
or fatura11_.DATA_VENCIMENTO<='2015-07-22' and conta10_.TIPO=2 and valorlanca1_.SITUACAO=1
or valorlanca1_.DATA_BAIXA<='2015-07-22' and conta10_.TIPO=2 and valorlanca1_.SITUACAO=3
)
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
和(
(valorlanca1.DATA_PREVISTA我需要查看您在CF_VALOR_LANCADO\u DETALHADO
和CF_VALOR_LANCADO
上创建的索引,但是您是否考虑过使用复合索引
?这允许您在多个列上创建索引
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
作为猜测,我将考虑创建一个
CF_VALOR_LANCADO.DATA_PREVISTA
和CF_VALOR_LANCADO.SITUACAO
对您的查询的解释一点也不差
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
您是否可以在MySQL服务器上运行这些SQL语句,并在此处发布结果,同时发布MySQL服务器版本?
通过这些语句,我们可以看到查询是CPU限制的还是I/O限制的
SET profiling = 1;
select SUM(valorlanca0_.VALOR_PREVISTO) as col_0_0_
from CF_VALOR_LANCADO_DETALHADO valorlanca0_
inner join CF_VALOR_LANCADO valorlanca1_ on valorlanca0_.ID_VALOR_LANCADO=valorlanca1_.ID_VALOR_LANCADO
inner join CF_LANCAMENTO lancamento2_ on valorlanca1_.ID_LANCAMENTO=lancamento2_.ID_LANCAMENTO
inner join CF_ADMINISTRACAO administra12_ on lancamento2_.ID_ADMINISTRACAO=administra12_.ID_ADMINISTRACAO
inner join CF_EMPRESA empresa13_ on lancamento2_.ID_EMPRESA=empresa13_.ID_EMPRESA
inner join CF_USUARIO usuario14_ on lancamento2_.ID_USUARIO_CRIOU=usuario14_.ID_USUARIO
left outer join CF_FORMA_PAGAMENTO formapagam9_ on valorlanca1_.ID_FORMA_PAGAMENTO=formapagam9_.ID_FORMA_PAGAMENTO
inner join CF_CONTA conta10_ on valorlanca1_.ID_CONTA=conta10_.ID_CONTA
left outer join CF_FATURA fatura11_ on valorlanca1_.ID_FATURA=fatura11_.ID_FATURA
left outer join CF_CATEGORIA categoria3_ on valorlanca0_.ID_CATEGORIA=categoria3_.ID_CATEGORIA
left outer join CF_CENTRO_CUSTO centrocust4_ on valorlanca0_.ID_CENTRO_CUSTO=centrocust4_.ID_CENTRO_CUSTO
left outer join CF_FAV_FONTE_PAGADORA favfontepa5_ on valorlanca0_.ID_FAV_FONTE_PAGADORA=favfontepa5_.ID_FAV_FONTE_PAGADORA
left outer join CF_CONTA_CONTABIL contaconta6_ on valorlanca0_.ID_CONTA_CONTABIL=contaconta6_.ID_CONTA_CONTABIL
left outer join CF_CONTATO contato7_ on valorlanca0_.ID_CONTATO=contato7_.ID_CONTATO
left outer join CF_MARCA marca8_ on valorlanca0_.ID_MARCA=marca8_.ID_MARCA
where administra12_.ID_ADMINISTRACAO=406 and lancamento2_.TIPO_CONTA=2 and (conta10_.ID_CONTA in (2060, 404, 405, 4291, 406, 410, 4292, 403, 4355, 402, 407)) and conta10_.TIPO<>9 and lancamento2_.TIPO_TRANSACAO=10
and (valorlanca1_.SITUACAO in (1)) and ((valorlanca1_.DATA_PREVISTA<='2015-07-22' and valorlanca1_.SITUACAO=1 or valorlanca1_.DATA_BAIXA<='2015-07-22' and valorlanca1_.SITUACAO=3)
and conta10_.TIPO<>2 or fatura11_.DATA_VENCIMENTO<='2015-07-22' and conta10_.TIPO=2 and valorlanca1_.SITUACAO=1 or valorlanca1_.DATA_BAIXA<='2015-07-22' and conta10_.TIPO=2 and valorlanca1_.SITUACAO=3)
and ((empresa13_.ID_EMPRESA in (422, 3643)) and usuario14_.ID_USUARIO=574 or empresa13_.ID_EMPRESA in (422, 3643));
SHOW PROFILES; # Displays an table with records use it to find your select profile id
SHOW PROFILE ALL FOR QUERY [select profile_id]
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
make_join_statistics()函数是一个很难运行的函数。我的建议是拆分查询,并尝试查看什么是较慢的连接
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
也有类似的事情
and **(valorlanca1_.SITUACAO in (1))**
and ((valorlanca1_.DATA_PREVISTA<='2015-07-22'
and **valorlanca1_.SITUACAO=1** or valorlanca1_.DATA_BAIXA<='2015-07-22'
and **valorlanca1_.SITUACAO=3**)
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
和**(第(1)段中的valorlanca1_.SITUACAO)**
和((valorlanca1_uuu.DATA_uprevista首先,我开始清理原始查询的格式,以查看表之间的相关性。然后我改为使用别名,将较长的表名简化为较短的表名,并得出了这个结论
select
SUM(V0.VALOR_PREVISTO) as col_0_0_
from
CF_VALOR_LANCADO_DETALHADO V0
inner join CF_VALOR_LANCADO V1
on V0.ID_VALOR_LANCADO = V1.ID_VALOR_LANCADO
inner join CF_LANCAMENTO L2
on V1.ID_LANCAMENTO = L2.ID_LANCAMENTO
inner join CF_ADMINISTRACAO A12
on L2.ID_ADMINISTRACAO = A12.ID_ADMINISTRACAO
inner join CF_EMPRESA E13
on L2.ID_EMPRESA = E13.ID_EMPRESA
inner join CF_USUARIO U14
on L2.ID_USUARIO_CRIOU = U14.ID_USUARIO
left outer join CF_FORMA_PAGAMENTO F9
on V1.ID_FORMA_PAGAMENTO = F9.ID_FORMA_PAGAMENTO
inner join CF_CONTA C10
on V1.ID_CONTA = C10.ID_CONTA
left outer join CF_FATURA F11
on V1.ID_FATURA = F11.ID_FATURA
left outer join CF_CATEGORIA C3
on V0.ID_CATEGORIA = C3.ID_CATEGORIA
left outer join CF_CENTRO_CUSTO C4
on V0.ID_CENTRO_CUSTO = C4.ID_CENTRO_CUSTO
left outer join CF_FAV_FONTE_PAGADORA F5
on V0.ID_FAV_FONTE_PAGADORA = F5.ID_FAV_FONTE_PAGADORA
left outer join CF_CONTA_CONTABIL C6
on V0.ID_CONTA_CONTABIL = C6.ID_CONTA_CONTABIL
left outer join CF_CONTATO C7
on V0.ID_CONTATO = C7.ID_CONTATO
left outer join CF_MARCA M8
on V0.ID_MARCA = M8.ID_MARCA
where
A12.ID_ADMINISTRACAO = 406
and L2.TIPO_CONTA = 2
and C10.ID_CONTA in (2060, 404, 405, 4291, 406, 410, 4292, 403, 4355, 402, 407)
and C10.TIPO <> 9
and L2.TIPO_TRANSACAO = 10
and V1.SITUACAO in (1)
and ( ( V1.DATA_PREVISTA <= '2015-07-22'
and V1.SITUACAO = 1
or V1.DATA_BAIXA <= '2015-07-22'
and V1.SITUACAO=3 )
and C10.TIPO <> 2
or F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1
or V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
and ( E13.ID_EMPRESA in (422, 3643)
and U14.ID_USUARIO = 574
or E13.ID_EMPRESA in (422, 3643) )
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
由于这里的最后一个OR条件与第一个相同,因此消除了ID_USUARIO=574的需要,并且可以简化为
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
and E13.ID_EMPRESA in (422, 3643)
您有几个左联接(功能上与“左外联接”相同)未在任何条件中使用…请删除它们,包括
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
LEFT JOIN CF_FORMA_PAGAMENTO
left join CF_CATEGORIA
left join CF_CENTRO_CUSTO
left join CF_CONTA_CONTABIL
left join CF_CONTATO
left join CF_MARCA
您使用的是左连接CF_FATURA fatura11_uu,并且它处于OR条件下,本质上是将其转换为内部连接,因为您不允许NULL,但是对于“DATA\u VENCIMENTO或
的显式测试有时会通过转换为UNION
进行优化:
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
SELECT ...
WHERE ((x=1) OR (y=2))
-->
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )
(UNION DISTINCT
比UNION ALL
慢,但您可能需要它进行重复数据消除。)根据查询计划,您的选择还不错。看起来您是I/O绑定的,您的硬盘是问题所在。MySQL必须找到硬盘上的记录,这显然是机械的,而且速度很慢。您是否使用InnoDB?如果是,您的InnoDB缓冲池大小是多少?
and C10.TIPO <> 2
or ( F11.DATA_VENCIMENTO <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 1 )
or ( V1.DATA_BAIXA <= '2015-07-22'
and C10.TIPO = 2
and V1.SITUACAO = 3 )