UNION vs LEFT JOIN...

  • Hi,

    I have a customer database that has a view with the following definition:

    CREATE VIEW [dbo].[V_Documentos]

    AS

    SELECT Movimentos.Id, Movimentos.Conta, Movimentos.ValorAlt, Movimentos.Dia, Movimentos.Diario, Movimentos.NumDiario, Movimentos.Documento,

    Movimentos.NumDoc, Movimentos.ContaOrigem, Movimentos.Descricao AS DescMov, Movimentos.Valor, Movimentos.Natureza, Movimentos.Iva,

    Movimentos.Selo, Movimentos.TipoConta, Movimentos.Entidade, Movimentos.Moeda, Movimentos.ClassOrgan, Movimentos.ContaOrc,

    Movimentos.Ano, PlanoContas.Descricao AS DescConta, Diarios.Descricao AS DescDiario, DocumentosCBL.Descricao AS DescDoc,

    Movimentos.Cambio, Movimentos.CambioOrigem, Movimentos.ValorOrigem, Movimentos.TipoAfectacao, Movimentos.CambioMAlt, Movimentos.Linha,

    Movimentos.Mes, Movimentos.IdCabec, Movimentos.PercNdedutivel, Movimentos.IvaAutoLiquidacao, Movimentos.TipoLancamento, TiposLancamento.Descricao AS DescTipoLancamento

    FROM dbo.Movimentos AS Movimentos INNER JOIN

    dbo.PlanoContas AS PlanoContas ON Movimentos.Ano = PlanoContas.Ano AND Movimentos.Conta = PlanoContas.Conta INNER JOIN

    dbo.Diarios AS Diarios ON Movimentos.Diario = Diarios.Diario LEFT OUTER JOIN

    dbo.DocumentosCBL AS DocumentosCBL ON Movimentos.Documento = DocumentosCBL.Documento

    INNER JOIN dbo.TiposLancamento AS TiposLancamento ON Movimentos.TipoLancamento = TiposLancamento.TipoLancamento

    WHERE (Movimentos.TipoConta <> 'O') AND (Movimentos.TipoConta <> 'C')

    UNION

    SELECT Movimentos.Id, Movimentos.Conta, Movimentos.ValorAlt, Movimentos.Dia, Movimentos.Diario, Movimentos.NumDiario, Movimentos.Documento,

    Movimentos.NumDoc, Movimentos.ContaOrigem, Movimentos.Descricao AS DescMov, Movimentos.Valor, Movimentos.Natureza, Movimentos.Iva,

    Movimentos.Selo, Movimentos.TipoConta, Movimentos.Entidade, Movimentos.Moeda, Movimentos.ClassOrgan, Movimentos.ContaOrc,

    Movimentos.Ano, PlanoCentros.Descricao AS DescConta, Diarios.Descricao AS DescDiario, DocumentosCBL.Descricao AS DescDoc,

    Movimentos.Cambio, Movimentos.CambioOrigem, Movimentos.ValorOrigem, Movimentos.TipoAfectacao, Movimentos.CambioMAlt, Movimentos.Linha,

    Movimentos.Mes, Movimentos.IdCabec, Movimentos.PercNdedutivel, Movimentos.IvaAutoLiquidacao, Movimentos.TipoLancamento, TiposLancamento.Descricao AS DescTipoLancamento

    FROM dbo.Movimentos AS Movimentos INNER JOIN

    dbo.PlanoCentros AS PlanoCentros ON Movimentos.Ano = PlanoCentros.Ano AND Movimentos.Conta = PlanoCentros.Centro INNER JOIN

    dbo.Diarios AS Diarios ON Movimentos.Diario = Diarios.Diario LEFT OUTER JOIN

    dbo.DocumentosCBL AS DocumentosCBL ON Movimentos.Documento = DocumentosCBL.Documento

    INNER JOIN dbo.TiposLancamento AS TiposLancamento ON Movimentos.TipoLancamento = TiposLancamento.TipoLancamento

    WHERE (Movimentos.TipoConta = 'O')

    UNION

    SELECT Movimentos.Id, Movimentos.Conta, Movimentos.ValorAlt, Movimentos.Dia, Movimentos.Diario, Movimentos.NumDiario, Movimentos.Documento,

    Movimentos.NumDoc, Movimentos.ContaOrigem, Movimentos.Descricao AS DescMov, Movimentos.Valor, Movimentos.Natureza, Movimentos.Iva,

    Movimentos.Selo, Movimentos.TipoConta, Movimentos.Entidade, Movimentos.Moeda, Movimentos.ClassOrgan, Movimentos.ContaOrc,

    Movimentos.Ano, PlanoFuncional.Descricao AS DescConta, Diarios.Descricao AS DescDiario, DocumentosCBL.Descricao AS DescDoc,

    Movimentos.Cambio, Movimentos.CambioOrigem, Movimentos.ValorOrigem, Movimentos.TipoAfectacao, Movimentos.CambioMAlt, Movimentos.Linha,

    Movimentos.Mes, Movimentos.IdCabec, Movimentos.PercNdedutivel, Movimentos.IvaAutoLiquidacao, Movimentos.TipoLancamento, TiposLancamento.Descricao AS DescTipoLancamento

    FROM dbo.Movimentos AS Movimentos INNER JOIN

    dbo.PlanoFuncional AS PlanoFuncional ON Movimentos.Ano = PlanoFuncional.Ano AND Movimentos.Conta = PlanoFuncional.Funcao INNER JOIN

    dbo.Diarios AS Diarios ON Movimentos.Diario = Diarios.Diario LEFT OUTER JOIN

    dbo.DocumentosCBL AS DocumentosCBL ON Movimentos.Documento = DocumentosCBL.Documento

    INNER JOIN dbo.TiposLancamento AS TiposLancamento ON Movimentos.TipoLancamento = TiposLancamento.TipoLancamento

    WHERE (Movimentos.TipoConta = 'C')

    Isn't this the same as having:

    SELECT Movimentos.Id, Movimentos.Conta, Movimentos.ValorAlt, Movimentos.Dia, Movimentos.Diario, Movimentos.NumDiario, Movimentos.Documento,

    Movimentos.NumDoc, Movimentos.ContaOrigem, Movimentos.Descricao AS DescMov, Movimentos.Valor, Movimentos.Natureza, Movimentos.Iva,

    Movimentos.Selo, Movimentos.TipoConta, Movimentos.Entidade, Movimentos.Moeda, Movimentos.ClassOrgan, Movimentos.ContaOrc,

    Movimentos.Ano, PlanoContas.Descricao AS DescConta, Diarios.Descricao AS DescDiario, DocumentosCBL.Descricao AS DescDoc,

    Movimentos.Cambio, Movimentos.CambioOrigem, Movimentos.ValorOrigem, Movimentos.TipoAfectacao, Movimentos.CambioMAlt, Movimentos.Linha,

    Movimentos.Mes, Movimentos.IdCabec, Movimentos.PercNdedutivel, Movimentos.IvaAutoLiquidacao, Movimentos.TipoLancamento, TiposLancamento.Descricao AS DescTipoLancamento

    FROM dbo.Movimentos AS Movimentos

    LEFT JOIN dbo.PlanoContas AS PlanoContas ON Movimentos.Ano = PlanoContas.Ano AND Movimentos.Conta = PlanoContas.Conta

    LEFT JOIN dbo.PlanoCentros AS PlanoCentros ON Movimentos.Ano = PlanoCentros.Ano AND Movimentos.Conta = PlanoCentros.Centro

    LEFT JOIN dbo.PlanoFuncional AS PlanoFuncional ON Movimentos.Ano = PlanoFuncional.Ano AND Movimentos.Conta = PlanoFuncional.Funcao

    INNER JOIN dbo.Diarios AS Diarios ON Movimentos.Diario = Diarios.Diario

    LEFT JOIN dbo.DocumentosCBL AS DocumentosCBL ON Movimentos.Documento = DocumentosCBL.Documento

    INNER JOIN dbo.TiposLancamento AS TiposLancamento ON Movimentos.TipoLancamento = TiposLancamento.TipoLancamento

    WHERE

    (Movimentos.TipoConta <> 'O' AND Movimentos.TipoConta <> 'C' AND PlanoContas.Ano IS NOT NULL)

    OR (Movimentos.TipoConta = 'O' AND PlanoCentros.Ano IS NOT NULL)

    OR (Movimentos.TipoConta = 'C' AND PlanoFuncional.Ano IS NOT NULL)

    The result is the same on both queries. The Execution plan gives 50% for each query... this means that both queries have the same "weight".... How can this be?!

    I then turn the statistics IO on and got this data:

    For the view with the UNION:

    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'PlanoContas'. Scan count 1, logical reads 142, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Movimentos'. Scan count 5, logical reads 66, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'TiposLancamento'. Scan count 3, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Diarios'. Scan count 1, logical reads 14, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'PlanoCentros'. Scan count 0, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'PlanoFuncional'. Scan count 0, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'DocumentosCBL'. Scan count 1, logical reads 15, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    For the other query, with the LEFT JOINs:

    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'PlanoContas'. Scan count 1, logical reads 142, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Movimentos'. Scan count 1, logical reads 46, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'TiposLancamento'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Diarios'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'PlanoCentros'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'PlanoFuncional'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'DocumentosCBL'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    The 2nd query has less logical reads... This is better right?!

    Thanks,

    Pedro



    If you need to work better, try working less...

  • That's not exactly the same result.

    This might do it, but I can't test it:

    SELECT Movimentos.Id,

    Movimentos.Conta,

    Movimentos.ValorAlt,

    Movimentos.Dia,

    Movimentos.Diario,

    Movimentos.NumDiario,

    Movimentos.Documento,

    Movimentos.NumDoc,

    Movimentos.ContaOrigem,

    Movimentos.Descricao AS DescMov,

    Movimentos.Valor,

    Movimentos.Natureza,

    Movimentos.Iva,

    Movimentos.Selo,

    Movimentos.TipoConta,

    Movimentos.Entidade,

    Movimentos.Moeda,

    Movimentos.ClassOrgan,

    Movimentos.ContaOrc,

    Movimentos.Ano,

    --Change in here

    COALESCE( PlanoContas.Descricao, PlanoCentros.Descricao, PlanoFuncional.Descricao) AS DescConta,

    Diarios.Descricao AS DescDiario,

    DocumentosCBL.Descricao AS DescDoc,

    Movimentos.Cambio,

    Movimentos.CambioOrigem,

    Movimentos.ValorOrigem,

    Movimentos.TipoAfectacao,

    Movimentos.CambioMAlt,

    Movimentos.Linha,

    Movimentos.Mes,

    Movimentos.IdCabec,

    Movimentos.PercNdedutivel,

    Movimentos.IvaAutoLiquidacao,

    Movimentos.TipoLancamento,

    TiposLancamento.Descricao AS DescTipoLancamento

    FROM dbo.Movimentos AS Movimentos

    LEFT JOIN dbo.PlanoContas AS PlanoContas ON Movimentos.Ano = PlanoContas.Ano

    AND Movimentos.Conta = PlanoContas.Conta

    AND Movimentos.TipoConta <> 'O' --Moved this from the WHERE clause

    AND Movimentos.TipoConta <> 'C' --Moved this from the WHERE clause

    LEFT JOIN dbo.PlanoCentros AS PlanoCentros ON Movimentos.Ano = PlanoCentros.Ano

    AND Movimentos.Conta = PlanoCentros.Centro

    AND Movimentos.TipoConta = 'O' --Moved this from the WHERE clause

    LEFT JOIN dbo.PlanoFuncional AS PlanoFuncional ON Movimentos.Ano = PlanoFuncional.Ano

    AND Movimentos.Conta = PlanoFuncional.Funcao

    AND Movimentos.TipoConta = 'C' --Moved this from the WHERE clause

    INNER JOIN dbo.Diarios AS Diarios ON Movimentos.Diario = Diarios.Diario

    LEFT JOIN dbo.DocumentosCBL AS DocumentosCBL ON Movimentos.Documento = DocumentosCBL.Documento

    INNER JOIN dbo.TiposLancamento AS TiposLancamento ON Movimentos.TipoLancamento = TiposLancamento.TipoLancamento

    Check where I did the changes and you'll have to evaluate which one will perform better. It depends on multiple things and you didn't provide enough information to check it.

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • Missed that column 🙂 Thanks.

    Now the execution plan is even weirder, since it says the UNION query is faster, but looking at the IO statistics that query has more logical reads than the LEFT JOIN one...



    If you need to work better, try working less...

Viewing 3 posts - 1 through 3 (of 3 total)

You must be logged in to reply to this topic. Login to reply