简体   繁体   中英

How to optimizing SQL Query with Cross Join

How can I make this SQL query more efficient? The CteFinal code shown below is a portion of my query which add up to 6 minutes to my query. The cteMonth is shown below. The cteDetail is another cte which pulls information directly from the database, and it takes less than a second to run.

What CteFinal is doing is creating missing fiscal period rows while including some of the column data from the row where f.FiscalPeriod=0.

I cannot add, delete, or change any of the indexes on the tables, as this is a ERP database and I'm not allowed to make those type of changes.

CteFinal:

SELECT      Account,Month, CONVERT(DATETIME, CAST(@Year as varchar(4)) + '-' + CAST(Month as VARCHAR(2)) + '-' + '01', 102) JEDate
        ,accountdesc,'' Description,'' JournalCode,NULL JournalNum,NULL JournalLine
        ,'' LegalNumber,'' CurrencyCode,0.00 DebitAmount,0.00 CreditAmount,fiscalcalendarid,company,bookid,SegValue2,SegValue1,SegValue3,SegValue4

FROM        cteDetail f
        CROSS JOIN cteMonths m

WHERE       f.FiscalPeriod=0 and not exists(select * from cteDetailADDCreatedZero x where x.Account=f.Account and x.FiscalPeriod=Month)

CteMonth:

cteMonths (Month) AS(
select 0 as Month
UNION select 1 as Month
UNION select 2 as Month
UNION select 3 as Month
UNION select 4 as Month
UNION select 5 as Month
UNION select 6 as Month
UNION select 7 as Month
UNION select 8 as Month
UNION select 9 as Month
UNION select 10 as Month
UNION select 11 as Month
UNION select 12 as Month)

Thank you!

Here's a slightly more efficient way to generate the 12 months of a given year (even more efficient if you have your own Numbers table ):

DECLARE @year INT = 2013;

;WITH cteMonths([Month],AsDate) AS
(
  SELECT n-1,DATEADD(YEAR, @Year-1900, DATEADD(MONTH,n-1,0)) FROM (
    SELECT TOP (13) RANK() OVER (ORDER BY [object_id]) FROM sys.all_objects
  ) AS c(n)
)
SELECT [Month], AsDate FROM cteMonths;

So now, you can say:

;WITH cteMonths([Month],AsDate) AS
(
  SELECT n,DATEADD(YEAR, @Year-1900, DATEADD(MONTH,n-1,0)) FROM (
    SELECT TOP (13) RANK() OVER (ORDER BY [object_id]) FROM sys.all_objects
  ) AS c(n)
), 
cteDetail AS 
(
  ...no idea what is here...
),
cteDetailADDCreatedZero AS
(
  ...no idea what is here...
)
SELECT f.Account, m.[Month], JEDate = m.AsDate, f.accountdesc, Description = '',
  JournalCode = '', JournalNum = NULL, JournalLine = NULL, LegalNumber = '', 
  CurrencyCode = '', DebitAmount = 0.00, CreditAmount = 0.00, f.fiscalcalendarid, 
  f.company, f.bookid, f.SegValue2, f.SegValue1, f.SegValue3, f.SegValue4
FROM cteMonths AS m
LEFT OUTER JOIN cteDetail AS f
ON ... some clause I am not clear on ...  
WHERE f.FiscalPeriod = 0 
AND NOT EXISTS 
(
  SELECT 1 FROM cteDetailADDCreatedZero AS x 
  WHERE x.Account = f.Account 
  AND x.FiscalPeriod = m.[Month]
);

I suspect this won't solve your problem though: it is likely that this is forcing an entire table scan on either whatever tables are mentioned in cteDetail or cteDetailADDCreatedZero or both. You should inspect the actual execution plan for this query and see if there are any scans or other expensive operations that could guide you towards better indexing. It also might just be that you have a bunch of inefficient CTEs stacked up together - we can't really help with that unless you show everything. CTEs are like views - if you start stacking them up on top of each other, you really limit the optimizer's ability to generate an efficient plan for you. At some point it will just throw its hands in the air...

One possibility is to physicalize the SQL View (if it the query is a view). Sometimes views with complex queries are slow.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM