Related
ALTER PROCEDURE [dbo].[TRN_Hold_GetData]
#XMLSearch XML = '<DocumentElement><TRN_Hold_GetData_Custom><HoldId>0</HoldId><FromDate>17-3-2017</FromDate><ToDate>17-2-2017</ToDate></TRN_Hold_GetData_Custom></DocumentElement>'
AS
BEGIN
DECLARE #HoldId INT = 0,
#HoldNo VARCHAR(50) = '',
#Party VARCHAR(100) = '',
#StoneNo VARCHAR(50) = '',
#FromDate VARCHAR(50) = '',
#ToDate VARCHAR(50) = '',
#HoldStatus VARCHAR(20) = '',
#FilterQry NVARCHAR(MAX) = '',
#FinalQry NVARCHAR(MAX) = ''
SELECT
#HoldNo = doc.col.value('HoldNo[1]', 'VARCHAR(50)'),
#Party = doc.col.value('Party[1]', 'VARCHAR(MAX)'),
#StoneNo = doc.col.value('StoneNo[1]', 'VARCHAR(MAX)'),
#FromDate = doc.col.value('FromDate[1]', 'VARCHAR(11)'),
#ToDate = doc.col.value('ToDate[1]', 'VARCHAR(11)'),
#HoldStatus = doc.col.value('HoldStatus[1]', 'VARCHAR(20)')
FROM
#XMLSearch.nodes('/DocumentElement/TRN_Hold_GetData_Custom') doc(col)
SELECT
convert(varchar(11), cast(OnHoldDate as datetime), 103),
ISNULL(TH.HoldId, '') AS HoldId,
ISNULL(TH.HoldNo, '') AS HoldNo,
ISNULL(TH.PartyId, '') AS PartyId,
ISNULL(MP.Party, '') AS Party,
ISNULL(TH.OnHoldDate, '') AS HoldDate,
ISNULL(TH.ExpReleaseDays, '') AS ExpReleaseDays,
ISNULL(TH.ExpReleaseDate, '') AS ExpReleaseDate,
ISNULL(TH.TotalPkt, '') AS TotalPkt,
ISNULL(TH.TotalCts, '') AS TotalCts,
HOLDSTONE, RELEASESTONE,
ISNULL(TH.TotalAmount, '') AS TotalAmount,
ISNULL(TH.HoldById, '') AS HoldById,
ISNULL(TH.Remark, '') AS Remark,
ISNULL(MEmp.firstname, '') + ' ' + ISNULL(MEmp.middlename, '') + ' ' + ISNULL(MEmp.lastname, '') AS HoldUser,
ISNULL(MEmp.firstname, '') + ' ' + ISNULL(MEmp.middlename, '') + ' ' + ISNULL(MEmp.lastname, '') AS UnHoldUser
FROM
dbo.TRN_Hold TH WITH ( NOLOCK )
INNER JOIN
( SELECT SUM(CASE WHEN HoldStatus = 0 THEN 1
ELSE 0
END) AS HOLDSTONE, SUM(CASE WHEN HoldStatus = 1 THEN 1
ELSE 0
END) AS RELEASESTONE, HoldId
FROM TRN_Hold_Detail
GROUP BY HoldId ) AS THD ON TH.HoldId = THD.HoldId
INNER JOIN TRN_Hold_Detail AS HDD WITH ( NOLOCK ) ON HDD.HoldId = THD.HoldId
INNER JOIN mst_Stone AS MS WITH ( NOLOCK ) ON HDD.StoneId = MS.Stone_id
LEFT JOIN MST_Party MP ON TH.PartyId = MP.party_id
LEFT JOIN MST_Employee MEmp ON TH.HoldById = MEmp.employee_id
WHERE HoldNo = (
CASE WHEN #HoldNo = '' or #HoldNo is null THEN HoldNo ELSE #HoldNo END ) AND
convert(varchar(11),cast(OnHoldDate as datetime),101)
between
CASE WHEN #FromDate= ''
THEN OnHoldDate
ELSE convert(varchar(11),#FromDate,101)
END
AND
CASE WHEN #ToDate = ''
THEN OnHoldDate
ELSE convert(varchar(11),#ToDate,101)
END
print #FromDate
print #ToDate
--????????????????????????????????????????????????????????????????
--AND ( CASE WHEN convert(varchar(50),cast(#FromDate as datetime),103)= ''
-- THEN convert(varchar(50),cast(#FromDate as datetime),103)
-- ELSE OnHoldDate
-- END ) >= convert(varchar(50),cast(#FromDate as datetime),103)
--AND ( CASE WHEN convert(varchar(50),cast(#ToDate as datetime),103) = ''
-- THEN convert(varchar(50),cast(#ToDate as datetime),103)
-- ELSE OnHoldDate
-- END ) <= convert(varchar(50),cast(#ToDate as datetime),103)
--????????????????????????????????????????????????????????????????
--AND ( #StoneNo = '' OR ms.Stone_no = #stoneNo )
-- --realse
--AND ((#HoldStatus = 'RELEASE' AND ISNULL(THD.HOLDSTONE, 0) = 0 AND ISNULL(THD.RELEASESTONE, 0) <> 0)
-- --Hold
--OR ( #HoldStatus = 'HOLD' AND ISNULL(THD.HOLDSTONE, 0) <> 0 AND ISNULL(THD.RELEASESTONE, 0) = 0)
-- --Partial
--OR (#HoldStatus = 'PARTIAL' AND ISNULL(THD.HOLDSTONE, 0) <> 0 AND ISNULL(THD.RELEASESTONE, 0) <> 0 )
--OR #HoldStatus = 'ALL'
-- )
-- print #FromDate
-- print convert(nvarchar(20), #FromDate ,106)
--print convert(nvarchar(20), #ToDate ,103)
--OnHoldDate between (case when #FromDate ='' then OnHoldDate else #FromDate end)
--and (case when #ToDate = '' then OnHoldDate else #ToDate end)
END
This is my stored proedure; when I execute it, I get the following error
Msg 242, Level 16, State 3, Procedure TRN_Hold_GetData, Line 45
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value
The DateTime in the XML "17-3-2017" can be interpreted in two different ways - one of which 3rd day of 17th month, is not valid. Make sure you use explicit date formats in your XML in line with XML standards (YYYY-MM-DDThh:mm:ss)
You really should have datetime strings in a universal format, as suggested by Phillip. However, if you do not have control this should properly handle your convert pattern:
declare #dAsStr varchar(max) = '17-3-2017'
select convert(datetime, #dAsStr, 105)
We found a slow query in our legacy system. What I see in the query is a duplicate fragment. Here's the full query:
DECLARE #SellerId INT;
DECLARE #DateFrom DATETIME;
DECLARE #DateTo DATETIME;
SET #SellerId = 5396884;
SET #DateFrom = '2016-01-05';
SET #DateTo = '2016-10-08';
DECLARE #CurrentDate DATETIME;
SET #CurrentDate = GETDATE();
CREATE TABLE #ReportDate (codes INT, dates DATETIME);
DECLARE #dif as INT;
DECLARE #cont as INT;
DECLARE #currdate as DATETIME;
SET #dif = DATEDIFF(day, #DateFrom, #DateTo);
SET #cont = 1;
SET #currdate = #DateFrom - 1;
WHILE (#cont <= #dif + 1)
BEGIN
SET #currdate = DATEADD(DAY, 1, #currdate);
INSERT INTO #ReportDate VALUES (#cont, #currdate);
SET #cont = #cont + 1;
END
/* HOW TO OPTIMIZE THIS ONE? */
SELECT
#ReportDate.dates as valid_date,
(
SELECT
COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives
FROM
(
SELECT *
FROM salesView
WHERE
salesView.sell_id NOT IN
(
SELECT sell_id
FROM salesStates
WHERE
salesStates.aborted = 1
)
) nonCancelledSales
WHERE
nonCancelledSales.seller_id = #SellerId AND
nonCancelledSales.cancelled = 0 AND
nonCancelledSales.void = 0 AND
nonCancelledSales.hasDiscount = 0 AND
nonCancelledSales.dateOfSale <= #ReportDate.dates AND
nonCancelledSales.currentState = (SELECT MAX(hveest.date)
FROM salesStates hveest
WHERE
hveest.sell_id = nonCancelledSales.sell_id AND
hveest.date <= #ReportDate.dates) AND
nonCancelledSales.lastProductDate = (SELECT MAX(hvepro.date)
FROM productHistory hvepro
WHERE
hvepro.sell_id = nonCancelledSales.sell_id AND
hvepro.date <= #ReportDate.dates)
) total_actives,
(
SELECT
ISNULL(SUM(nonCancelledSales.paymentValue),0) as active
FROM
(
SELECT *
FROM salesView
WHERE
salesView.sell_id NOT IN
(
SELECT sell_id
FROM salesStates
WHERE
salesStates.aborted = 1
)
) nonCancelledSales
WHERE
nonCancelledSales.seller_id = #SellerId AND
nonCancelledSales.cancelled = 0 AND
nonCancelledSales.void = 0 AND
nonCancelledSales.hasDiscount = 0 AND
nonCancelledSales.dateOfSale <= #ReportDate.dates AND
nonCancelledSales.currentState = (SELECT MAX(hveest.date)
FROM salesStates hveest
WHERE
hveest.sell_id = nonCancelledSales.sell_id AND
hveest.date <= #ReportDate.dates) AND
nonCancelledSales.lastProductDate = (SELECT MAX(hvepro.date)
FROM productHistory hvepro
WHERE
hvepro.sell_id = nonCancelledSales.sell_id AND
hvepro.date <= #ReportDate.dates)
) active
FROM
#ReportDate
GROUP BY
#ReportDate.dates
DROP TABLE #ReportDate
Here are the two duplicated fragments I see:
(
SELECT
COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives
FROM
(
SELECT *
FROM salesView
WHERE
salesView.sell_id NOT IN
(
SELECT sell_id
FROM salesStates
WHERE
salesStates.aborted = 1
)
) nonCancelledSales
WHERE
nonCancelledSales.seller_id = #SellerId AND
nonCancelledSales.cancelled = 0 AND
nonCancelledSales.void = 0 AND
nonCancelledSales.hasDiscount = 0 AND
nonCancelledSales.dateOfSale <= #ReportDate.dates AND
nonCancelledSales.currentState = (SELECT MAX(hveest.date)
FROM salesStates hveest
WHERE
hveest.sell_id = nonCancelledSales.sell_id AND
hveest.date <= #ReportDate.dates) AND
nonCancelledSales.lastProductDate = (SELECT MAX(hvepro.date)
FROM productHistory hvepro
WHERE
hvepro.sell_id = nonCancelledSales.sell_id AND
hvepro.date <= #ReportDate.dates)
) total_actives,
(
SELECT
ISNULL(SUM(nonCancelledSales.paymentValue),0) as active
FROM
(
SELECT *
FROM salesView
WHERE
salesView.sell_id NOT IN
(
SELECT sell_id
FROM salesStates
WHERE
salesStates.aborted = 1
)
) nonCancelledSales
WHERE
nonCancelledSales.seller_id = #SellerId AND
nonCancelledSales.cancelled = 0 AND
nonCancelledSales.void = 0 AND
nonCancelledSales.hasDiscount = 0 AND
nonCancelledSales.dateOfSale <= #ReportDate.dates AND
nonCancelledSales.currentState = (SELECT MAX(hveest.date)
FROM salesStates hveest
WHERE
hveest.sell_id = nonCancelledSales.sell_id AND
hveest.date <= #ReportDate.dates) AND
nonCancelledSales.lastProductDate = (SELECT MAX(hvepro.date)
FROM productHistory hvepro
WHERE
hvepro.sell_id = nonCancelledSales.sell_id AND
hvepro.date <= #ReportDate.dates)
) active
Is it fully necessary to duplicate the query ? In the first one he's getting:
COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives
on the second one:
ISNULL(SUM(nonCancelledSales.paymentValue),0) as active
I suppose there has to be some way to rewrite the query but I'm not sure how.
You can combine these, if you use OUTER APPLY.
The idea is:
SELECT . . ., x.actives, x.active
FROM #ReportDate OUTER APPLY
(SELECT COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives,
COALESCE(SUM(nonCancelledSales.paymentValue), 0) as active
. . . -- rest of query here
) x;
In this case, OUTER APPLY is a lot like a correlated subquery in the FROM clause that can return multiple rows.
My query has this structure:
SELECT DISTINCT (CO.CateringOrderId),
CO.CateringOrderNumber,
MC.FirstName + ' ' + MC.LastName AS "CustomerName",
CO.EventDate AS EventDate,
CO.IsCompleted,
CO.IsVerified,
MC.EmailId,
CAT.OfficePhone,
CAT.Mobile,
CAT.Fax,
CO.TotalInvoiceAmount,
CO.BarterCharityId,
(SELECT Sum (Amount)
FROM Catering_Order_Payment_Trans
WHERE CateringOrderId = CO.CateringOrderId) AS AmountReceived
FROM Catering_Orders CO,
Master_Customer MC,
Customer_Address_Trans CAT,
Catering_Order_Employee_Trans COET
WHERE MC.CompanyId = #p_CompanyId
AND (MC.CustomerId = #p_CustomerId OR #p_CustomerId = -1)
AND (CO.CateringOrderNumber LIKE '%' + #p_CateringOrderNumber + '%')
AND (CO.EventDate >= CONVERT (DATETIME, #p_FromDate) OR #p_FromDate = '')
AND (CO.EventDate <= CONVERT (DATETIME, #p_ToDate) OR #p_ToDate = '')
AND (CO.IsCompleted = #p_IsCompleted OR #p_IsCompleted = -1)
AND (COET.EmployeeId = #p_CatererId OR #p_CatererId = -1)
AND MC.CustomerId = CO.CustomerId
AND MC.PersonalAddressId = CAT.CustomerAddressId
AND (COET.CateringOrderId = CO.CateringOrderId
OR CO.CateringOrderId NOT IN
(SELECT CateringOrderId FROM Catering_Order_Employee_Trans))
AND (CAT.Mobile like '%' + #p_ContactNumber + '%' )
AND (CO.IsActive is null or CO.IsActive=1)
ORDER BY CO.CateringOrderId DESC
I think the SUM sub-query is slowing it. Please suggest me on how to speed it up.
Currently its execution time is around 7 - 10 seconds.
Try something like this -
SELECT DISTINCT
CO.CateringOrderId,
CO.CateringOrderNumber,
MC.FirstName + ' ' + MC.LastName AS CustomerName,
CO.EventDate AS EventDate,
CO.IsCompleted,
CO.IsVerified,
MC.EmailId,
CAT.OfficePhone,
CAT.Mobile,
CAT.Fax,
CO.TotalInvoiceAmount,
CO.BarterCharityId,
AmountReceived = (
SELECT SUM(t.Amount)
FROM dbo.Catering_Order_Payment_Trans t
WHERE t.CateringOrderId = CO.CateringOrderId
)
FROM (
SELECT *
FROM dbo.Catering_Orders
WHERE ISNULL(IsActive, 1) = 1
AND (IsCompleted = #p_IsCompleted OR #p_IsCompleted = -1)
AND CateringOrderNumber LIKE '%' + #p_CateringOrderNumber + '%'
AND EventDate BETWEEN
CONVERT(DATETIME, ISNULL(NULLIF(#p_FromDate, ''), '18000101'))
AND
CONVERT(DATETIME, ISNULL(NULLIF(#p_ToDate, ''), '30000101'))
) CO
JOIN dbo.Master_Customer MC ON MC.CustomerId = CO.CustomerId
JOIN dbo.Customer_Address_Trans CAT ON MC.PersonalAddressId = CAT.CustomerAddressId
LEFT JOIN (
SELECT *
FROM dbo.Catering_Order_Employee_Trans
WHERE EmployeeId = #p_CatererId
OR #p_CatererId = -1
) COET ON COET.CateringOrderId = CO.CateringOrderId
WHERE MC.CompanyId = #p_CompanyId
AND (MC.CustomerId = #p_CustomerId OR #p_CustomerId = -1)
AND CAT.Mobile LIKE '%' + #p_ContactNumber + '%'
The main problems in
AND (COET.CateringOrderId = CO.CateringOrderId
OR CO.CateringOrderId NOT IN
(SELECT CateringOrderId FROM Catering_Order_Employee_Trans))
and
(SELECT Sum (Amount)
FROM Catering_Order_Payment_Trans
WHERE CateringOrderId = CO.CateringOrderId) AS AmountReceived
Try:
SELECT CO.CateringOrderId,
CO.CateringOrderNumber,
MC.FirstName + ' ' + MC.LastName AS "CustomerName",
CO.EventDate AS EventDate,
CO.IsCompleted,
CO.IsVerified,
MC.EmailId,
CAT.OfficePhone,
CAT.Mobile,
CAT.Fax,
CO.TotalInvoiceAmount,
CO.BarterCharityId,
COPT.AmountReceived
FROM Catering_Orders CO
JOIN Master_Customer MC ON MC.CustomerId = CO.CustomerId
JOIN Customer_Address_Trans CAT ON MC.PersonalAddressId = CAT.CustomerAddressId
LEFT JOIN (SELECT CateringOrderId, Sum(Amount) AS AmountReceived
FROM Catering_Order_Payment_Trans
GROUP BY CateringOrderId) COPT
ON COPT.CateringOrderId = CO.CateringOrderId
WHERE MC.CompanyId = #p_CompanyId
AND (MC.CustomerId = #p_CustomerId OR #p_CustomerId = -1)
AND (CO.CateringOrderNumber LIKE '%' + #p_CateringOrderNumber + '%')
AND (CO.EventDate >= CONVERT (DATETIME, #p_FromDate) OR #p_FromDate = '')
AND (CO.EventDate <= CONVERT (DATETIME, #p_ToDate) OR #p_ToDate = '')
AND (CO.IsCompleted = #p_IsCompleted OR #p_IsCompleted = -1)
AND EXISTS
(SELECT NULL
FROM Catering_Order_Employee_Trans COET
WHERE COET.CateringOrderId = CO.CateringOrderId AND
(COET.EmployeeId = #p_CatererId OR #p_CatererId = -1) )
AND (CAT.Mobile like '%' + #p_ContactNumber + '%' )
AND (CO.IsActive is null or CO.IsActive=1)
ORDER BY CO.CateringOrderId DESC
To optimize your query you should edit the OR condition inserted inside AND conditions which really slow down your query
AND ( CO.EventDate <= CONVERT (DATETIME, #p_ToDate)
OR #p_ToDate = '')
should become something like
AND ( CO.EventDate <= CASE WHEN #p_ToDate = '' THEN
GETDATE()
ELSE
CONVERT (DATETIME,#p_ToDate)
END)
Also try to remove one by one the innested select both in select and in where to see which one most slows down the query
Here is the story: I have to implement filter. And in this filter there are certain categories I filter by.
One of the filters is "favourite" filter (#includeFavourites ).
I have this huge SQL with paging and sorting and everything.
Now, when "includeFavourites" option in filter is clicked, then I also have to select unique ID's from different table (this entries are stored in different datatable), where favourites are stored.
I have tried left outer join, but it returns "number of favourites" records for each record in primary table. Coalesce didn't help at all.
Here is my SQL:
--this is needed because stored procedure must know how many days are selected
DECLARE #daysCount int
SET #daysCount = 0
IF (#mon IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#tue IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#wed IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#thu IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#fri IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#sat IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
IF (#sun IS NOT NULL)
BEGIN
SET #daysCount = #daysCount+1
END
-- Insert statements for procedure here
SELECT * FROM (
SELECT ROW_NUMBER() OVER
(
ORDER BY
CASE WHEN #OrderBy = 'ND' THEN title END DESC,
CASE WHEN #OrderBy = 'NA' THEN title END,
CASE WHEN #OrderBy = '' THEN title END,
CASE WHEN #OrderBy = 'RD' THEN authorRating END DESC,
CASE WHEN #OrderBy = 'RA' THEN authorRating
) AS Row,
Articles.ArticleId, Articles.userId, Articles.timestamp as datePosted, users.screenName,
defaultSmallImagePath, authorRating, ArticleCosts, title,
FROM Articles
LEFT OUTER JOIN
Users on Articles.userId = Users.userId
LEFT OUTER JOIN
ArticleAdditionalInformation ON ArticleAdditionalInformation.ArticleId = Articles.ArticleId
--JOIN FOR CONTINENT
LEFT OUTER JOIN
Codings as Continent ON Continent.codingKeyId = ArticleAdditionalInformation.continentId AND Continent.languageId = #languageId
-- JOIN FOR COUNTRY
LEFT OUTER JOIN
CodingsAssociated as Country ON Country.codingKeyId = ArticleAdditionalInformation.countryId AND Country.languageId = #languageId
-- JOIN FOR Article TRANSLATION DATA
LEFT OUTER JOIN
ArticlesTranslations ON ArticlesTranslations.ArticleId = Articles.ArticleId AND ArticlesTranslations.languageId=#languageId
LEFT OUTER JOIN
ArticleCategories ON ArticleCategories.ArticleId = Articles.ArticleId
WHERE
(
ArticleCategories.categorieId =1 OR ArticleCategories.categorieId =2 OR
ArticleCategories.categorieId =3 OR ArticleCategories.categorieId =4 OR
ArticleCategories.categorieId = 5
) AND
(ArticlesTranslations.title LIKE '%' + #searchString + '%' OR #searchString IS NULL)
-- COST filter
AND
(ArticleCosts < #cost OR #cost = 0)
AND
(ArticleCosts > 0 OR #cost = 0)
--END cost filter
-- EXCLUDE already stored for selected days
AND Articles.ArticleId -- exclude these ArticleIds
NOT IN
(
SELECT DailyContent.ArticleId
FROM DailyContent
WHERE
sectionId=#sectionId AND
(
weekDayId=#mon OR
weekDayId=#tue OR
weekDayId=#wed OR
weekDayId=#thu OR
weekDayId=#fri OR
weekDayId=#sat OR
weekDayId=#sun
)
GROUP BY
DailyContent.ArticleId
HAVING
(COUNT(sectionId) = #daysCount)
)
-- END exclude
) p
WHERE (Row > #startRowIndex AND Row <=#startRowIndex + #pageSize)
ORDER BY Row
END
So, I would only like to include unique articleIds from favourite table, when #includeFavourites parameter is not null.
Any hint would be greatly appreciated ;)
I am using SQL server 2008.
Try this one -
DECLARE #daysCount INT
SELECT #daysCount =
ISNULL(#mon, 0) + -- if #mon = 1, #tue = 2, .... 1 + (2-1)=1 + (3-2)=1 + ...
ISNULL(#tue - 1, 0) +
ISNULL(#wed - 2, 0) +
ISNULL(#thu - 3, 0) +
ISNULL(#fri - 4, 0) +
ISNULL(#sat - 5, 0) +
ISNULL(#sun - 6, 0)
SELECT *
FROM (
SELECT ROW_NUMBER() OVER
(
ORDER BY
CASE WHEN #OrderBy = 'ND' THEN title END DESC,
CASE WHEN #OrderBy IN ('NA', '') THEN title END,
CASE WHEN #OrderBy = 'RD' THEN authorRating END DESC,
CASE WHEN #OrderBy = 'RA' THEN authorRating
) AS [Row]
, a.ArticleId
, a.userId
, a.[timestamp] as datePosted
, u.screenName
, defaultSmallImagePath
, authorRating
, ArticleCosts
, title
FROM dbo.Articles a -- always use schema and alias
LEFT JOIN dbo.Users u on a.userId = u.userId -- OUTER is unnecessary
LEFT JOIN dbo.ArticleAdditionalInformation aai ON aai.ArticleId = a.ArticleId
LEFT JOIN dbo.Codings cd ON cd.codingKeyId = aai.continentId AND cd.languageId = #languageId
LEFT JOIN dbo.CodingsAssociated c ON c.codingKeyId = aai.countryId AND c.languageId = #languageId
LEFT JOIN dbo.ArticlesTranslations at ON at.ArticleId = a.ArticleId AND at.languageId = #languageId
LEFT JOIN dbo.ArticleCategories ac ON ac.ArticleId = a.ArticleId
WHERE ac.categorieId IN (1, 2, 3, 4, 5)
AND (
at.title LIKE '%' + #searchString + '%'
OR
#searchString IS NULL
)
AND (ArticleCosts < #cost OR #cost = 0)
AND (ArticleCosts > 0 OR #cost = 0)
AND a.ArticleId NOT IN (
SELECT dc2.ArticleId
FROM dbo.DailyContent dc2
WHERE sectionId = #sectionId
AND (
weekDayId % #daysCount = 0 -- possible it's works
--weekDayId = #mon OR
--weekDayId = #tue OR
--weekDayId = #wed OR
--weekDayId = #thu OR
--weekDayId = #fri OR
--weekDayId = #sat OR
--weekDayId = #sun
)
GROUP BY dc2.ArticleId
HAVING COUNT(sectionId) = #daysCount
)
) p
WHERE [Row] BETWEEN #startRowIndex AND #startRowIndex + #pageSize
--ORDER BY [Row] -- ROW_COUNT already sorted your rows
I have the store sql
ALTER procedure [dbo].[TNNews_User_SearchBasic]
#Title nvarchar(400),
#CategoryId int,
#IsInterested int,
#IsHot int,
#IsTopCategory int,
#IsPublish int,
#PageSize int,
#PageIndex int,
#OrderBy varchar(20),
#PortalId int,
#LanguageId varchar(6)
as
DECLARE #EndTime DATETIME
DECLARE #StartTime DATETIME
SET #StartTime = GETDATE()
declare #tbCategory table(Id int)
DECLARE #StartRowIndex INT
IF #PageSize=0 SELECT #PageSize=count(*) FROM TNNews
IF(#PageIndex<0) SET #PageIndex=0
SET #StartRowIndex = #PageSize*(#PageIndex-1)+1
;WITH tmpCategory(Id, Name,ParentId,Level)
AS (
SELECT
e.Id,
e.Name,
e.ParentId,
1
FROM dbo.TNCategory AS e
WHERE
Id = #CategoryId or (#CategoryId='' and ParentId<=0)
UNION ALL
SELECT
e.Id,
e.Name,
e.ParentId,
Level + 1
FROM dbo.TNCategory AS e
JOIN tmpCategory AS d ON e.ParentId = d.Id
)
insert #tbCategory select Id from tmpCategory
;WITH tmpNews as
(
SELECT
a.Id,a.Title,a.Subject
,ROW_NUMBER() OVER (ORDER BY (Publisheddate) desc) as ThuTuBanGhi
FROM dbo.TNNews a
where 1 = 1
--and ( Title like '%'+#Title+'%')
and (#CategoryId = -1 or exists (select 0 from #tbCategory b where b.Id = a.CategoryId))
and (#IsInterested = -1 or IsIntrested = #IsInterested )
and (#IsHot = -1 or IsHot = #IsHot )
and (#IsTopCategory = -1 or IsTopCategory = #IsTopCategory )
and (#IsPublish = -1 or IsPublished = #IsPublish)
and PortalId=#PortalId
and LanguageId = #LanguageId
)
select *, (select COUNT(Id) from tmpNews) as 'TongSoBanGhi' from tmpNews
WHERE
ThuTuBanGhi BETWEEN (#StartRowIndex) AND (#StartRowIndex + #PageSize-1)
SET #EndTime = GETDATE()
PRINT 'StartTime = ' + CONVERT(VARCHAR(30),#StartTime,121)
PRINT ' EndTime = ' + CONVERT(VARCHAR(30),#EndTime,121)
PRINT ' Duration = ' + STR(DATEDIFF(MILLISECOND,#StartTime,#EndTime)) + ' millisecond'
select STR(DATEDIFF(MILLISECOND,#StartTime,#EndTime))
After this store excute
EXEC [dbo].[TNNews_User_SearchBasic]
#Title='',
#CategoryId = '',
#IsInterested = -1,
#IsHot = -1,
#IsTopCategory = -1,
#IsPublish = -1,
#PageSize = 20,
#PageIndex = 1,
#OrderBy = '',
#PortalId = 0,
#LanguageId = N'vi-VN'
go
The time excute about "200ms". And I create a new store "TNNews_User_SearchBasic1" with some change.
.....
--,ROW_NUMBER() OVER (ORDER BY (Publisheddate) desc) as ThuTuBanGhi
,ROW_NUMBER() OVER (ORDER BY (case when #OrderBy='VIEW_COUNT' then ViewCount else PublishedDate end) desc) as ThuTuBanGhi
.....
and now the time excute this store
EXEC [dbo].[TNNews_User_SearchBasic1]
#Title='',
#CategoryId = '',
#IsInterested = -1,
#IsHot = -1,
#IsTopCategory = -1,
#IsPublish = -1,
#PageSize = 20,
#PageIndex = 1,
#OrderBy = '',
#PortalId = 0,
#LanguageId = N'vi-VN'
GO
about 900ms.
I don't understand why there is a change. Please help me improve these stores.
PS: I put example db at: http://anhquan22.tk/Portals/0/Videos/web.rar
Finished analysis the structure of your database. The part of the problem is hiding in the table structure.
I have prepared a backup for you. In it, I slightly modified scheme to improve performance and some normalize the table. You can download it from this link.
...to your question, I would do like this -
DECLARE #SQL NVARCHAR(1000)
SELECT #SQL = N'
;WITH tmpCategory (Id, Name, ParentId, [Level]) AS
(
SELECT
e.Id
, e.Name
, e.ParentId
, 1
FROM dbo.TNCategory e
WHERE Id = #CategoryId OR (#CategoryId = '''' AND ParentId <= 0)
UNION ALL
SELECT
e.Id
, e.Name
, e.ParentId
, [Level] + 1
FROM dbo.TNCategory e
JOIN tmpCategory d ON e.ParentId = d.Id
)
SELECT
a.Id
, ROW_NUMBER() OVER (ORDER BY ' +
CASE WHEN #OrderBy = 'VIEW_COUNT'
THEN 'ViewCount'
ELSE 'PublishedDate'
END +' DESC) AS ThuTuBanGhi
FROM dbo.TNNewsMain a
where PortalId = #PortalId
AND LanguageId = #LanguageId'
+ CASE WHEN #IsInterested != -1 THEN ' AND IsInterested = #IsInterested' ELSE '' END
+ CASE WHEN #IsHot != -1 THEN ' AND IsHot = #IsHot' ELSE '' END
+ CASE WHEN #IsTopCategory != -1 THEN ' AND IsTopCategory = #IsTopCategory' ELSE '' END
+ CASE WHEN #IsPublish != -1 THEN ' AND IsPublish = #IsPublish' ELSE '' END
+ CASE WHEN #CategoryId != -1 THEN '' ELSE ' AND EXISTS(SELECT 1 FROM tmpCategory b WHERE b.Id = a.CategoryId)' END
INSERT INTO #temp (Id, ThuTuBanGhi)
EXECUTE sp_executesql
#SQL
, N'#PortalId INT
, #LanguageId VARCHAR(6)
, #CategoryId INT
, #IsInterested INT
, #IsHot INT
, #IsTopCategory INT
, #IsPublish INT'
, #PortalId = #PortalId
, #LanguageId = #LanguageId
, #CategoryId = #CategoryId
, #IsInterested = #IsInterested
, #IsHot = #IsHot
, #IsTopCategory = #IsTopCategory
, #IsPublish = #IsPublish;
SELECT
d.Id
, tm.Title
, tm.[Subject]
, d.ThuTuBanGhi
, c.TongSoBanGhi
FROM (
SELECT t.Id
, t.ThuTuBanGhi
FROM #temp t
WHERE t.ThuTuBanGhi BETWEEN #StartRowIndex AND #StartRowIndex + #PageSize - 1
) d
JOIN TNNewsMain tm ON d.Id = tm.Id
CROSS JOIN (
SELECT TongSoBanGhi = (SELECT COUNT(1) FROM #temp)
) c