我有我要优化的查询

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ComprobantesFacturasObtenerEstadisticasLocal2]
(
    @FechaDesde DateTime,
    @FechaHasta DateTime,
    @XML ntext
)
AS
BEGIN

    DECLARE @docHandler INT

    EXEC sp_xml_preparedocument @docHandler OUTPUT, @XML

    --Locales
    Select IdLocal
    into #seleccionados
    FROM OPENXML(@docHandler, N'/NewDataSet/Table1', 2)
    WITH (IdLocal int)

    select d.* into #Locales from  Dim_Sucursal d inner join GrimRepCen..Locales l on l.Codigo = d.Codigo inner join #seleccionados s on s.IdLocal = l.iDlocal

    /*2011/12/06 busco los descuentos del rio*/
    select distinct l.Codigo + ' - ' + l.Nombre  as local, c.IdComprobante, -1 as Cantidad,
        -1 * isnull(abs(c.TotalNeto),0) as IMPORTE,
        'Varios' as Familia, 'Dto Bco Rio' as Linea
    into #descuentoRio
    from Fact_Comprobante(nolock) c
    --inner join Fact_ComprobanteItem(nolock) ci on ci.IdComprobante = c.IdComprobante
    inner join #locales l  on c.idDim_ComprobanteTipo = 5  and l.IdDim_sucursal = c.IdDim_sucursal  and c.fecha between @FechaDesde and @FechaHasta

    /*******************COMPROBANTES************************************************ */
    select distinct
        c.*, l.Codigo + ' - ' + l.Nombre  as local, ct.IdComprobanteTipo
    into #Comprobantes
    from Fact_Comprobante(nolock) c
    inner join Fact_ComprobanteItem(nolock) ci on ci.IdCOmprobante = c.IdComprobante
    inner join Dim_ComprobanteTipo(nolock) ct on ct.IdDim_ComprobanteTipo = c.idDim_ComprobanteTipo
    inner join #locales l on l.IdDim_sucursal = c.IdDim_sucursal and  ct.IdComprobanteTipo not in (46 /*Error Fiscal Factura B*/, 47 /*Error Fiscal Factura A*/) and c.fecha between @FechaDesde and @FechaHasta

     --Comprobantes por Linea/Marca/Familia
    select
        m.Nombre as Marca, l.Nombre as Linea , case  when c.IdComprobanteTipo in (21,23,26,28) then 0 else -sum(ci.Cantidad) end as Cantidad,
        case  when c.IdComprobanteTipo in (21,23,26,28)

        --toma en cuenta los descuentos de las facturas que fueron anuladas
        then c.TotalNeto
        else isnull(ci.ImporteNeto,0) - isnull((select sum(importe) as importe
                                                from Fact_Descuento (nolock) DD
                                                where DD.IdComprobante = ci.idComprobante  and ci.IdDim_Producto = IdDim_Producto
                                                 and ci.IdDim_Medida = IdDim_Medida and ci.IdDim_Calidad = IdDim_Calidad
                                                 and exists
                                                     (
                                                        select 1
                                                        from ComprobanteReferencias AA
                                                        inner join Fact_Comprobante BB on aa.IdComprobanteCredito = BB.IdComprobante
                                                        where AA.IdComprobanteDebito = DD.IdComprobante
                                                        and BB.IdDim_ComprobanteTipo in (4,13,16,19)
                                                     )
                                                 ),0)
        end as IMPORTE,
        f.Nombre as Familia
    from #Comprobantes c
    inner join Fact_ComprobanteItem(nolock) ci on  ci.IdComprobante = c.IdComprobante
    inner join Dim_Producto(nolock) p on p.IdDim_Producto = ci.IdDim_Producto
    inner join Dim_Marca(nolock) m on m.IdDim_Marca = p.IDDim_Marca
    inner join Dim_Familia(nolock) f on f.idDim_Familia = p.IdDim_Familia
    inner join Dim_Linea(nolock) l on l.IdDim_Linea = p.IdDim_Linea
    Group by m.Nombre,l.Nombre,f.Nombre,c.TotalNeto,ci.IdComprobante, ci.IdDim_producto,
    ci.idDim_Medida,ci.ImporteNeto,c.IdComprobanteTipo  ,ci.IdDim_Calidad
    union all
    select 'Grimoldi' as Marca, Linea , - 1 Cantidad,
        IMPORTE,
        Familia
    from #descuentoRio

    --/*Familia*/
    select case  when c.IdComprobanteTipo in (21,23,26,28) then 0 else -isnull(sum(ci.Cantidad),0) end as Cantidad,
    case  when c.IdComprobanteTipo in (21,23,26,28)

        --toma en cuenta los descuentos de las facturas que fueron anuladas
        then c.TotalNeto
        else isnull(ci.ImporteNeto,0) - isnull((select sum(importe) as importe
                                                from Fact_Descuento (nolock) DD
                                                where DD.IdComprobante = ci.idComprobante  and ci.IdDim_Producto = IdDim_Producto
                                                 and ci.IdDim_Medida = IdDim_Medida and ci.IdDim_Calidad = IdDim_Calidad
                                                 and exists
                                                     (
                                                        select 1
                                                        from ComprobanteReferencias AA
                                                        inner join Fact_Comprobante BB on aa.IdComprobanteCredito = BB.IdComprobante
                                                        where AA.IdComprobanteDebito = DD.IdComprobante
                                                        and BB.IdDim_ComprobanteTipo in (4,13,16,19)
                                                     )
                                                 ),0)
        end as IMPORTE,
        f.Nombre as Familia
    from #Comprobantes c
    inner join Comprobantes(nolock) co on co.IdComprobante = c.IdComprobante
    inner join Fact_ComprobanteItem(nolock) ci on  ci.IdComprobante = c.IdComprobante
    inner join Dim_Producto(nolock) p on p.IdDim_Producto = ci.IdDim_Producto
    full outer join Dim_Familia(nolock) f on f.idDim_Familia = p.IdDim_Familia
    Group by f.Nombre,ci.ImporteNeto,ci.IdComprobante, ci.IdDim_producto,
    ci.idDim_Medida,c.TotalNeto, c.IdComprobanteTipo    ,ci.IdDim_Calidad
    union all
    select  -1 as Cantidad,
        IMPORTE,
        Familia
     from #descuentoRio

    /*local*/
    select c.Local, case  when c.IdComprobanteTipo in (21,23,26,28) then 0 else -isnull((sum(ci.Cantidad)),0) end as Cantidad,
        case  when c.IdComprobanteTipo in (21,23,26,28)

        --toma en cuenta los descuentos de las facturas que fueron anuladas
        then c.TotalNeto
        else isnull(ci.ImporteNeto,0) - isnull((select sum(importe) as importe
                                                from Fact_Descuento (nolock) DD
                                                where DD.IdComprobante = ci.idComprobante  and ci.IdDim_Producto = IdDim_Producto
                                                 and ci.IdDim_Medida = IdDim_Medida and ci.IdDim_Calidad = IdDim_Calidad
                                                 and exists
                                                     (
                                                        select 1
                                                        from ComprobanteReferencias AA
                                                        inner join Fact_Comprobante BB on aa.IdComprobanteCredito = BB.IdComprobante
                                                        where AA.IdComprobanteDebito = DD.IdComprobante
                                                        and BB.IdDim_ComprobanteTipo in (4,13,16,19)
                                                     )
                                                 ),0)
    end as IMPORTE,
    f.Nombre as Familia, l.Nombre as Linea
    from #Comprobantes c
    inner join Comprobantes(nolock) co on co.IdComprobante = c.IdComprobante
    inner join Fact_ComprobanteItem(nolock) ci on  ci.IdComprobante = c.IdComprobante
    inner join Dim_Producto(nolock) p on p.IdDim_Producto = ci.IdDim_Producto
    inner join Dim_Linea(nolock) l on l.IdDim_Linea = p.IdDim_Linea
    inner join Dim_Familia(nolock) f on f.idDim_Familia = p.IdDim_Familia
    Group by f.Nombre,ci.ImporteNeto, l.Nombre  ,ci.IdComprobante, ci.IdDim_producto,
    ci.idDim_Medida, c.Local,c.TotalNeto, c.IdComprobanteTipo,ci.IdDim_Calidad
    union all
    select Local, -1 as Cantidad,
        IMPORTE,
        Familia, Linea
     from #descuentoRio
end

有些事情我无法更改,例如,以其他方式(而不是xml)发送ID(因为我必须修改代码而我不能),表的结构和其他内容。我只能修改此存储的。
该查询接收一些Id,插入到临时表(#Seleccionados)中,并使用它执行一些Joins以获取有关销售的信息以及其他信息。
此外,您还可以看到奇怪的事物,如带有已编码值的Union ALL和其他事物。那是因为代码中报告的完成方式,并且也无法更改(我的意思是,不要担心那些奇怪的事情)。
此存储的内容基本上返回4个选择:其中一个仅是一行,因此我遇到了另外3个问题,在这里向您展示。

我尝试了什么:

我当时想的是尝试解决一些重复的问题,例如,此子查询:
(select sum(importe) as importe
                                                from Fact_Descuento (nolock) DD
                                                where DD.IdComprobante = ci.idComprobante  and ci.IdDim_Producto = IdDim_Producto
                                                 and ci.IdDim_Medida = IdDim_Medida and ci.IdDim_Calidad = IdDim_Calidad
                                                 and exists
                                                     (
                                                        select 1
                                                        from ComprobanteReferencias AA
                                                        inner join Fact_Comprobante BB on aa.IdComprobanteCredito = BB.IdComprobante
                                                        where AA.IdComprobanteDebito = DD.IdComprobante
                                                        and BB.IdDim_ComprobanteTipo in (4,13,16,19)
                                                     )
                                                 )

ISNULL中,对3个选择重复了该子句。因此,我想可以和WITH Common_Expresion_Table一起使用并减少它。但是,该选择是它的子查询,因此取决于我使用子查询时选择的值(可以在该子查询的where子句中看到我在说什么)

然后我尽管如此,这3个选择并没有太大的不同。他们有几次重复的联接,但是以不同的方式分组。因此,我也想使用某种临时表或CTE,但是我不确定,因为它们是用不同的方式分组的,并且还有一两个不同的JOINS
一些额外的信息:
#Seleccionados将具有100行ID。
此查询需要50段。一个星期:
  • 第一个查询返回47083 rows
  • 第二个查询返回47084 rows
  • 第三个查询返回47084 rows

  • 如您所见,它几乎是相同的信息,只是以不同的方式分组。

    表格:Fact_Comprobante获得了有关一次销售的信息。有关销售商品的Fact_ComprobanteItemDim_Producto获取有关一种产品的信息,Dim_Familia获取有关产品系列的信息,Dim_Marca获取有关产品标志的信息,Dim_Linea获取有关产品行的信息(这3个表在Dim_Producto中为FK)。Dim_ComprobanteTipo获取有关销售类型的信息Fact_Descuento获取有关折扣的信息,与销售有关。

    所有表都有很多信息。
    (Nolock)语句是因为在这些表中我们同时有3个服务插入,更新和其他内容。

    我没有执行此查询,我只需要对其进行优化。

    最佳答案

    使用SQL事件探查器(如果可以访问它)并过滤存储过程的名称。确保显示每个步骤(因此运行该过程将产生1或2行以上)。然后,在每个步骤上,您都会看到秒数的nr,读取,写入的nr等。因此,您可以专注于耗时的部分。

    您可以使用以下SQL分析配置文件:

    declare @dStart datetime
    set @dStart = getdate()
    
    -- at every place you like to monitor
    print 'a: ' + convert(nvarchar(datediff(ms, @dStart, getdate()))
    

    不深入该过程,我将从子查询开始
    并且存在
    (
    ...

    那可能是一个昂贵的,而不是重写为左或右联接

    关于sql-server - 优化具有重复信息的查询,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11453405/

    10-11 21:56
    查看更多