Sql-server – Query Speed CTE Or View

postgresqlsql-server-2008-r2t-sql

We have a postgresql database that I am using OPENQUERY to query from a SQL Server 2008 R2 install. From an optimization standpoint is it quicker to

OPTION 1:

1) Create a view of the postgresql data on SQL Server

2) Write a CTE to aggregate the data from the view & query

OPTION 2:

1) Write a CTE using OPENQUERY and aggregate the data in one query

I have run tests using both methods and in the instances I ran there is roughly a 2 – 3 second difference with either way. In the guru's opinions what is the quickest/less resource intensive way to run a query of this nature?

****And let me add that since the views are created from using OPENQUERY there is no way to index the views.

    SELECT *
FROM OPENQUERY(555.187.331.191,'WITH CTE_Employee AS
    (
        select 
        cm.empID As employeeID
        ,RTRIM(LTRIM(cm.employeeName)) As employeeName
        ,cm.employeeStatus As employeeStatus
        FROM employee cm
        WHERE employeeStatus IN (''I'', ''A'', ''R'', ''F'')
        ORDER BY employeeName ASC
    )
    , CTE_TSA AS
    (
        Select
        cm.employeeName employee
        ,SUM(CAST(COALESCE(rl.salesamount,0) AS DOUBLE PRECISION)) As "TotalSaleAmount"
        ,rc.saleDate TransDate
        FROM saleLog rc
        JOIN saleLogLine rl
        ON rc.saleID = rl.saleLog
        JOIN saleType sc
        ON rl.saleType = sc.saleTypeID
        JOIN employee cm
        ON rc.empID = cm.empID
        WHERE rl.saleLog = rc.saleID
        AND sc.saleVerified = ''True''
        AND rc.saleDate BETWEEN ''2017-01-01'' AND ''2017-01-31''
        GROUP BY cm.employeeName,rc.saleDate
    )
    , CTE_TB AS
    (
        Select 
        cm.employeeName employee
        ,SUM(CAST(COALESCE(jc.bonusAmt,0) AS DOUBLE PRECISION)) As totalBonus
        ,jc.saleID saleID
        ,iv.saleDate saleDate
        FROM saleBonus jc
        INNER JOIN saleBonusStructure ac
        ON jc.saleID = ac.saleID
        LEFT OUTER JOIN saleCategory wp
        ON wp.saleCatID = ac.saleCatID
        Left join sales iv
        ON jc.saleID = iv.saleID
        LEFT JOIN hoursWorkred jb
        ON jc.saleID = jb.saleID
        INNER JOIN employee cm
        ON cm.empID = jb.empID
        WHERE (ac.ice) 
        AND jc.saleID IN (Select saleID from sales)
        AND iv.saleDate BETWEEN ''2017-01-01'' AND ''2017-01-31''
        GROUP BY cm.employeeName,jc.saleID,iv.saleDate
    )
    , CTE_Tres AS
    (
        SELECT hoursWorkredarchive.saleID,
        CAST(SUM(hoursWorkredarchive.actualSaleAmt) AS DOUBLE PRECISION) "ActualAmt"
        ,employee.employeeName As "employee"
        ,hoursWorkredarchive.saleDate
        ,hoursWorkredarchive.saleDescription
        FROM  ((hoursWorkredarchive hoursWorkredarchive 
        LEFT OUTER JOIN employee employee 
        ON hoursWorkredarchive.empID=employee.empID ) 
        LEFT OUTER JOIN salesperson salesperson 
        ON hoursWorkredarchive.salesid=salesperson.salesid )  
        LEFT OUTER JOIN hoursWorkred hoursWorkred 
        ON hoursWorkredarchive.saleID=hoursWorkred.saleID 
        WHERE ((hoursWorkredarchive.saleDate BETWEEN ''2017-01-01'' AND ''2017-01-31''))
        GROUP BY hoursWorkredarchive.saleID,employee.employeeName,hoursWorkredarchive.saleDate, hoursWorkredarchive.empID, hoursWorkred.hoursWorkredtype,hoursWorkredarchive.saleDescription
        ORDER BY hoursWorkredarchive.empID, hoursWorkred.hoursWorkredtype, employee.employeeName
    )
    , CTE_TotalSales AS
    (
        with MaxVerNumber as
        (   
            select max(saleVersionNumber) as "MaxSaleNumber"   
            ,saleNumber    
            from sales    
            group by saleNumber
        )
        select 
        es.saleNumber As "saless"
        ,cm.employeeName employeeName
        ,es.saleDate saleDate
        FROM MaxVerNumber vn
        INNER JOIN sales es
        ON vn.saleNumber=es.saleNumber
        AND COALESCE(vn."MaxSaleNumber",0)=COALESCE(es.saleVersionNumber,0)
        INNER JOIN employee cm
        ON es.employeeID = cm.empID
        WHERE es.saleDate BETWEEN ''2017-01-01'' AND ''2017-01-31''
    )
    , CTE_hoursWorked As
    (
        Select 
        iv.saleID As hoursWorked
        ,cm.empID employeeID
        ,cm.employeeName employeeName
        ,iv.saleDate saleDate
        from sales iv
        INNER JOIN hoursWorkred jb
        ON jb.saleID = iv.saleID
        INNER JOIN employee cm
        ON cm.empID = jb.empID
        WHERE iv.saleDate BETWEEN ''2017-01-01'' AND ''2017-01-31''
        GROUP BY cm.empID, cm.employeeName, hoursWorked, iv.saleDate
    )
    , CTE_salessUnder500 As
    (
        WITH salesAmt AS 
            (Select 
            cm.employeeName As "employee"
            ,jb.saleID saleID
            ,CAST(COALESCE(jp.saleAmt,0) As DOUBLE PRECISION) salesAmt
            ,CAST(jp.ccsaleDate As Date) saleDate
            FROM hoursWorkredpart jp
            Inner Join hoursWorkred jb
            on jp.saleID = jb.saleID
            Inner join employee cm
            on cm.empID = jb.empID
            WHERE jp.ccsaleDate BETWEEN ''2017-01-01'' AND ''2017-01-31''
            AND cm.employeeStatus IN (''I'', ''A'', ''R'', ''F''),
            employees As
            (select 
            cm.employeeName As employee
            ,cm.employeeStatus As employeeStatus
            FROM employee cm
            ORDER BY employee ASC)
            Select
            DISTINCT(RTRIM(LTRIM(employee))) As "employeeName"
            ,COUNT(1) AS "Count"
            FROM employees cm
            JOIN (
            Select
            RTRIM(LTRIM("employee")) As employee
            ,SUM(salesAmt) As "TotalsalesAmt"
            ,saleDate
            ,saleID
            FROM salesAmt 
            GROUP BY RTRIM(LTRIM("employee")),saleDate,saleID
            ) As ia
            ON RTRIM(LTRIM(ia.employee)) = RTRIM(LTRIM(cm.employee))
            WHERE CAST(saleDate As Date) BETWEEN ''2017-01-01'' AND ''2017-01-31''
                AND "TotalsalesAmt" <= ''500.00''
                GROUP BY "employeeName"
    )
    , CTE_saless As
    (
        WITH salesAmt AS 
            (Select 
            cm.employeeName employee
            ,jb.saleID saleID
            ,CAST(COALESCE(jp.saleAmt,0) As DOUBLE PRECISION) salesAmt
            ,CAST(jp.ccsaleDate As Date) saleDate
            FROM hoursWorkredpart jp
            Inner Join hoursWorkred jb
            on jp.saleID = jb.saleID
            Inner join employee cm
            on cm.empID = jb.empID
            WHERE jp.ccsaleDate BETWEEN ''2017-01-01'' AND ''2017-01-31''
            AND cm.employeeStatus IN (''I'', ''A'', ''R'', ''F''),,
            employees As
            (select 
            cm.employeeName As employee
            ,cm.employeeStatus As employeeStatus
            FROM employee cm
            ORDER BY employee ASC)
            Select
            DISTINCT(RTRIM(LTRIM(employee))) As "employeeName"
            ,COUNT(1) AS "Count"
            FROM employees cm
            JOIN (
            Select
            RTRIM(LTRIM(employee)) As employee
            ,SUM(salesAmt) As "TotalsalesAmt"
            ,saleDate
            ,saleID
            FROM salesAmt 
            GROUP BY RTRIM(LTRIM(employee)),saleDate,saleID
            ) As ia
            ON RTRIM(LTRIM(ia.employee)) = RTRIM(LTRIM(cm.employee))
            WHERE CAST(saleDate As Date) BETWEEN ''2017-01-01'' AND ''2017-01-31''
                GROUP BY "employeeName"
    )
SELECT S.employeeName
    , COUNT(JB.hoursWorked) As "NumberOfhoursWorkreds"
    , COUNT(ES."saless") As "NumberOfsaless"
    , COALESCE(IU500."Count",0) As "salessUnder500"
    , COALESCE(IV."Count",0) As "saless"
    , CAST(COALESCE(TR."TotalSaleAmount",0) AS INT) As "TotalSales"
    , CAST(COALESCE(TR."TotalSaleAmount",0) AS INT)-COALESCE(TF.totalBonus,0) As "EmpBenefit"
    , COALESCE(TF.totalBonus,0) As "FreightRev"
    , COALESCE(TF.totalBonus,0)*.75 As "FreightCost"
    , (COALESCE(CAST(TR."TotalSaleAmount" AS DOUBLE PRECISION),0)-COALESCE(CAST(TF.totalBonus  AS DOUBLE PRECISION),0))+(COALESCE(CAST(TF.totalBonus AS DOUBLE PRECISION),0)*.75) As "Log1"
    , COALESCE(CAST(DAC."ActualAmt" AS DOUBLE PRECISION),0) As "Log2"
    , COALESCE(CAST(TR."TotalSaleAmount" AS DOUBLE PRECISION),0)-COALESCE(CAST(DAC."ActualAmt" AS DOUBLE PRECISION),0) As "Log3"
    , case
            when CAST((COALESCE(CAST(TR."TotalSaleAmount" AS DOUBLE PRECISION) ,0)-COALESCE(CAST(DAC."ActualAmt" AS DOUBLE PRECISION),0))/NULLIF(COALESCE(CAST(TR."TotalSaleAmount" AS DOUBLE PRECISION),0),0) AS DECIMAL(10,2)) IS NULL THEN ''0.00''
            else CAST((COALESCE(CAST(TR."TotalSaleAmount" AS DOUBLE PRECISION) ,0)-COALESCE(CAST(DAC."ActualAmt" AS DOUBLE PRECISION),0))/NULLIF(COALESCE(CAST(TR."TotalSaleAmount" AS DOUBLE PRECISION),0),0) AS DECIMAL(10,2))
      end As "Log4"
    FROM CTE_Employee AS S
    LEFT OUTER JOIN CTE_TSA AS TR ON TR.employee = S.employeeName
    LEFT OUTER JOIN CTE_TB AS TF ON TF.employee = S.employeeName
    LEFT OUTER JOIN CTE_Tres AS DAC ON DAC."employee" = S.employeeName
    LEFT OUTER JOIN CTE_TotalSales AS ES ON ES.employeeName = S.employeeName
    LEFT OUTER JOIN CTE_hoursWorked AS JB ON JB.employeeName = S.employeeName
    LEFT OUTER JOIN CTE_salessUnder500 AS IU500 ON IU500."employeeName" = S.employeeName
    LEFT OUTER JOIN CTE_saless AS IV ON IV."employeeName" = S.employeeName
GROUP BY S.employeeName, IU500."Count",IV."Count",TR."TotalSaleAmount",TF."totalBonus",dac."ActualAmt"
ORDER BY S.employeeName ASC')

Best Answer

Doing aggregations of remote data in a SQL Server view is going to be expensive, because SQL Server will have to first copy the un-aggregated data to the SQL Server (in memory/tempdb) before it can do the aggregation you want.

If at all possible, do the aggregation on the PostgreSQL side. Create a view in the Postgres DB that does any GROUP BYs you need, and then select from that view on the SQL Server side.