Splitting SQL query with many joins into smaller ones helps? - sql

We need to do some reporting every night on our SQL server 2008R2. Calculating the reports takes several hours. In order to shorten the time we precalculate a table. This table is created based on JOINining 12 quite big (tens of milions row) tables.
The calculation of this aggregation table took until few days ago cca 4 hours. Our DBA than split this big join into 3 smaller joins (each joining 4 tables). The temporar result is everytime saved into a temporary table, which is used in the next join.
The result of the DBA enhancment is, that the aggregation table is calculated in 15 minutes. I wondered how is that possible. DBA told me that it is because the number of data the server must process is smaller. In other words, that in the big original join the server has to work with more data than in summed smaller joins. However, I would presume that optimizer would take care of doing it effeciently with the original big join, splitting the joins on its own and sending only the number of columns needed to next joins.
The other thing he has done is that he created an index on one of the tmeporary tables. However, once again I would think that the optimizer will create the appropriate hash tables if needed and alltogether better optimize the computation.
I talked about this with our DBA, but he was himself uncertain about what cased the improvement in processing time. He just mentioned, that he would not blame the server as it can be overwhelming to compute such big data and that it is possible that the optimizer has hard time to predict the best execution plan ... . This I understand, but I would like to have more defining answer as to exactly why.
So, the questions are:
1. "What could possibly cause the big improvement?"
2. "Is it a standard procedure to split big joins into smaller?"
3. "Is the amount of data which srever has to process really smaller in case of multiple smaller joins?"
Here is the original query:
Insert Into FinalResult_Base
SELECT
TC.TestCampaignContainerId,
TC.CategoryId As TestCampaignCategoryId,
TC.Grade,
TC.TestCampaignId,
T.TestSetId
,TL.TestId
,TSK.CategoryId
,TT.[TestletId]
,TL.SectionNo
,TL.Difficulty
,TestletName = Char(65+TL.SectionNo) + CONVERT(varchar(4),6 - TL.Difficulty)
,TQ.[QuestionId]
,TS.StudentId
,TS.ClassId
,RA.SubjectId
,TQ.[QuestionPoints]
,GoodAnswer = Case When TQ.[QuestionPoints] Is null Then 0
When TQ.[QuestionPoints] > 0 Then 1
Else 0 End
,WrongAnswer = Case When TQ.[QuestionPoints] = 0 Then 1
When TQ.[QuestionPoints] Is null Then 1
Else 0 End
,NoAnswer = Case When TQ.[QuestionPoints] Is null Then 1 Else 0 End
,TS.Redizo
,TT.ViewCount
,TT.SpentTime
,TQ.[Position]
,RA.SpecialNeeds
,[Version] = 1
,TestAdaptationId = TA.Id
,TaskId = TSK.TaskId
,TaskPosition = TT.Position
,QuestionRate = Q.Rate
,TestQuestionId = TQ.Guid
,AnswerType = TT.TestletAnswerTypeId
FROM
[TestQuestion] TQ WITH (NOLOCK)
Join [TestTask] TT WITH (NOLOCK) On TT.Guid = TQ.TestTaskId
Join [Question] Q WITH (NOLOCK) On TQ.QuestionId = Q.QuestionId
Join [Testlet] TL WITH (NOLOCK) On TT.TestletId = TL.Guid
Join [Test] T WITH (NOLOCK) On TL.TestId = T.Guid
Join [TestSet] TS WITH (NOLOCK) On T.TestSetId = TS.Guid
Join [RoleAssignment] RA WITH (NOLOCK) On TS.StudentId = RA.PersonId And RA.RoleId = 1
Join [Task] TSK WITH (NOLOCK) On TSK.TaskId = TT.TaskId
Join [Category] C WITH (NOLOCK) On C.CategoryId = TSK.CategoryId
Join [TimeWindow] TW WITH (NOLOCK) On TW.Id = TS.TimeWindowId
Join [TestAdaptation] TA WITH (NOLOCK) On TA.Id = TW.TestAdaptationId
Join [TestCampaign] TC WITH (NOLOCK) On TC.TestCampaignId = TA.TestCampaignId
WHERE
T.TestTypeId = 1 -- eliminuji ankety
And t.ProcessedOn is not null -- ne vsechny, jen dokoncene
And TL.ShownOn is not null
And TS.Redizo not in (999999999, 111111119)
END;
The new splitted joins after DBA great work:
SELECT
TC.TestCampaignContainerId,
TC.CategoryId As TestCampaignCategoryId,
TC.Grade,
TC.TestCampaignId,
T.TestSetId
,TL.TestId
,TL.SectionNo
,TL.Difficulty
,TestletName = Char(65+TL.SectionNo) + CONVERT(varchar(4),6 - TL.Difficulty) -- prevod na A5, B4, B5 ...
,TS.StudentId
,TS.ClassId
,TS.Redizo
,[Version] = 1 -- ?
,TestAdaptationId = TA.Id
,TL.Guid AS TLGuid
,TS.TimeWindowId
INTO
[#FinalResult_Base_1]
FROM
[TestSet] [TS] WITH (NOLOCK)
JOIN [Test] [T] WITH (NOLOCK)
ON [T].[TestSetId] = [TS].[Guid] AND [TS].[Redizo] NOT IN (999999999, 111111119) AND [T].[TestTypeId] = 1 AND [T].[ProcessedOn] IS NOT NULL
JOIN [Testlet] [TL] WITH (NOLOCK)
ON [TL].[TestId] = [T].[Guid] AND [TL].[ShownOn] IS NOT NULL
JOIN [TimeWindow] [TW] WITH (NOLOCK)
ON [TW].[Id] = [TS].[TimeWindowId] AND [TW].[IsActive] = 1
JOIN [TestAdaptation] [TA] WITH (NOLOCK)
ON [TA].[Id] = [TW].[TestAdaptationId] AND [TA].[IsActive] = 1
JOIN [TestCampaign] [TC] WITH (NOLOCK)
ON [TC].[TestCampaignId] = [TA].[TestCampaignId] AND [TC].[IsActive] = 1
JOIN [TestCampaignContainer] [TCC] WITH (NOLOCK)
ON [TCC].[TestCampaignContainerId] = [TC].[TestCampaignContainerId] AND [TCC].[IsActive] = 1
;
SELECT
FR1.TestCampaignContainerId,
FR1.TestCampaignCategoryId,
FR1.Grade,
FR1.TestCampaignId,
FR1.TestSetId
,FR1.TestId
,TSK.CategoryId AS [TaskCategoryId]
,TT.[TestletId]
,FR1.SectionNo
,FR1.Difficulty
,TestletName = Char(65+FR1.SectionNo) + CONVERT(varchar(4),6 - FR1.Difficulty) -- prevod na A5, B4, B5 ...
,FR1.StudentId
,FR1.ClassId
,FR1.Redizo
,TT.ViewCount
,TT.SpentTime
,[Version] = 1 -- ?
,FR1.TestAdaptationId
,TaskId = TSK.TaskId
,TaskPosition = TT.Position
,AnswerType = TT.TestletAnswerTypeId
,TT.Guid AS TTGuid
INTO
[#FinalResult_Base_2]
FROM
#FinalResult_Base_1 FR1
JOIN [TestTask] [TT] WITH (NOLOCK)
ON [TT].[TestletId] = [FR1].[TLGuid]
JOIN [Task] [TSK] WITH (NOLOCK)
ON [TSK].[TaskId] = [TT].[TaskId] AND [TSK].[IsActive] = 1
JOIN [Category] [C] WITH (NOLOCK)
ON [C].[CategoryId] = [TSK].[CategoryId]AND [C].[IsActive] = 1
;
DROP TABLE [#FinalResult_Base_1]
CREATE NONCLUSTERED INDEX [#IX_FR_Student_Class]
ON [dbo].[#FinalResult_Base_2] ([StudentId],[ClassId])
INCLUDE ([TTGuid])
SELECT
FR2.TestCampaignContainerId,
FR2.TestCampaignCategoryId,
FR2.Grade,
FR2.TestCampaignId,
FR2.TestSetId
,FR2.TestId
,FR2.[TaskCategoryId]
,FR2.[TestletId]
,FR2.SectionNo
,FR2.Difficulty
,FR2.TestletName
,TQ.[QuestionId]
,FR2.StudentId
,FR2.ClassId
,RA.SubjectId
,TQ.[QuestionPoints] -- 1+ good, 0 wrong, null no answer
,GoodAnswer = Case When TQ.[QuestionPoints] Is null Then 0
When TQ.[QuestionPoints] > 0 Then 1 -- cookie
Else 0 End
,WrongAnswer = Case When TQ.[QuestionPoints] = 0 Then 1
When TQ.[QuestionPoints] Is null Then 1
Else 0 End
,NoAnswer = Case When TQ.[QuestionPoints] Is null Then 1 Else 0 End
,FR2.Redizo
,FR2.ViewCount
,FR2.SpentTime
,TQ.[Position] AS [QuestionPosition]
,RA.SpecialNeeds -- identifikace SVP
,[Version] = 1 -- ?
,FR2.TestAdaptationId
,FR2.TaskId
,FR2.TaskPosition
,QuestionRate = Q.Rate
,TestQuestionId = TQ.Guid
,FR2.AnswerType
INTO
[#FinalResult_Base]
FROM
[#FinalResult_Base_2] FR2
JOIN [TestQuestion] [TQ] WITH (NOLOCK)
ON [TQ].[TestTaskId] = [FR2].[TTGuid]
JOIN [Question] [Q] WITH (NOLOCK)
ON [Q].[QuestionId] = [TQ].[QuestionId] AND [Q].[IsActive] = 1
JOIN [RoleAssignment] [RA] WITH (NOLOCK)
ON [RA].[PersonId] = [FR2].[StudentId]
AND [RA].[ClassId] = [FR2].[ClassId] AND [RA].[IsActive] = 1 AND [RA].[RoleId] = 1
drop table #FinalResult_Base_2;
truncate table [dbo].[FinalResult_Base];
insert into [dbo].[FinalResult_Base] select * from #FinalResult_Base;
drop table #FinalResult_Base;

For the first, please, rebuilding indexes on your tables by this script (this may take a long time) -
SET NOCOUNT ON;
DECLARE
#SQL NVARCHAR(MAX)
, #IndexName SYSNAME
, #Output VARCHAR(200)
, #ServerVersion VARCHAR(100)
SELECT #ServerVersion = CAST(SERVERPROPERTY('Edition') AS VARCHAR(100))
DECLARE cur CURSOR LOCAL READ_ONLY FORWARD_ONLY FOR
SELECT
'ALTER INDEX [' + ix.name + N'] ON [' + SCHEMA_NAME(t.[schema_id]) + '].[' + t.name + '] ' +
CASE
WHEN ps.avg_fragmentation_in_percent > 50 THEN
CASE WHEN #ServerVersion LIKE 'Enterprise%' OR #ServerVersion LIKE 'Developer%' THEN
'REBUILD WITH (SORT_IN_TEMPDB = ON, ONLINE = ON ' + CASE WHEN ix.fill_factor > 0 THEN ', FILLFACTOR = ' + CAST(ix.fill_factor AS VARCHAR(3)) ELSE '' END + ') '
ELSE
'REBUILD WITH (SORT_IN_TEMPDB = ON' + CASE WHEN ix.fill_factor > 0 THEN ', FILLFACTOR = ' + CAST(ix.fill_factor AS VARCHAR(3)) ELSE '' END + ') '
END
ELSE 'REORGANIZE '
END +
CASE
WHEN ps.partition_number > 1 THEN N' PARTITION = ' + CAST(ps.partition_number AS NVARCHAR(MAX))
ELSE N''
END + ';', ix.name
FROM sys.indexes ix
JOIN sys.objects t ON t.[object_id] = ix.[object_id]
JOIN (
SELECT
[object_id]
, index_id
, avg_fragmentation_in_percent
, partition_number
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, N'LIMITED')
WHERE page_count > 100
AND avg_fragmentation_in_percent > 10
) ps ON t.[object_id] = ps.[object_id] AND ix.index_id = ps.index_id
WHERE t.[type] = 'U'
AND t.name IN (
'TestQuestion', 'TestTask', 'Question', 'Testlet',
'Test', 'TestSet', 'RoleAssignment', 'Task',
'category', 'TimeWindow', 'TestAdaptation', 'TestCampaign')
OPEN cur
FETCH NEXT FROM cur INTO #SQL, #IndexName
WHILE ##FETCH_STATUS = 0 BEGIN
SELECT #Output = CONVERT(NVARCHAR(15), GETDATE(), 114) + ': ' + #IndexName
RAISERROR(#Output, 0, 1) WITH NOWAIT
EXEC sys.sp_executesql #SQL
FETCH NEXT FROM cur INTO #SQL, #IndexName
END
CLOSE cur
DEALLOCATE cur
And after it try this query -
INSERT INTO dbo.FinalResult_Base
SELECT
TC.TestCampaignContainerId
, TestCampaignCategoryId = TC.CategoryID
, TC.Grade
, TC.TestCampaignId
, T.TestSetId
, TL.TestId
, TSK.CategoryID
, TT.[TestletId]
, TL.SectionNo
, TL.Difficulty
, TestletName = CHAR(65 + TL.SectionNo) + CONVERT(VARCHAR(4), 6 - TL.Difficulty)
, TQ.[QuestionId]
, TS.StudentId
, TS.ClassId
, RA.SubjectId
, TQ.[QuestionPoints]
, GoodAnswer =
CASE WHEN ISNULL(TQ.[QuestionPoints], 0) > 0
THEN 1
ELSE 0
END
, WrongAnswer =
CASE
WHEN ISNULL(TQ.[QuestionPoints], 0) = 0
THEN 1
ELSE 0
END
, NoAnswer =
CASE WHEN TQ.[QuestionPoints] IS NULL
THEN 1
ELSE 0
END
, TS.Redizo
, TT.ViewCount
, TT.SpentTime
, TQ.[Position]
, RA.SpecialNeeds
, [Version] = 1
, TestAdaptationId = TA.id
, TaskId = TSK.TaskId
, TaskPosition = TT.Position
, QuestionRate = Q.Rate
, TestQuestionId = TQ.guid
, AnswerType = TT.TestletAnswerTypeId
FROM dbo.TestQuestion TQ WITH (NOLOCK)
JOIN dbo.TestTask TT WITH (NOLOCK) ON TT.[guid] = TQ.TestTaskId
JOIN dbo.Question Q WITH (NOLOCK) ON TQ.QuestionId = Q.QuestionId
JOIN (
SELECT *
FROM dbo.Testlet TL WITH (NOLOCK)
WHERE TL.ShownOn IS NOT NULL
) TL ON TT.TestletId = TL.[guid]
JOIN (
SELECT *
FROM dbo.Test T WITH (NOLOCK)
WHERE T.TestTypeId = 1
AND T.ProcessedOn IS NOT NULL
) T ON TL.TestId = T.[guid]
JOIN (
SELECT *
FROM dbo.TestSet TS WITH (NOLOCK)
WHERE TS.Redizo NOT IN (999999999, 111111119)
) TS ON T.TestSetId = TS.[guid]
JOIN dbo.RoleAssignment RA WITH (NOLOCK) ON TS.StudentId = RA.PersonID AND RA.RoleId = 1
JOIN dbo.Task TSK WITH (NOLOCK) ON TSK.TaskId = TT.TaskId
JOIN dbo.category C WITH (NOLOCK) ON C.CategoryID = TSK.CategoryID
JOIN dbo.TimeWindow TW WITH (NOLOCK) ON TW.id = TS.TimeWindowId
JOIN dbo.TestAdaptation TA WITH (NOLOCK) ON TA.id = TW.TestAdaptationId
JOIN dbo.TestCampaign TC WITH (NOLOCK) ON TC.TestCampaignId = TA.TestCampaignId
And try this query -
SELECT TC.TestCampaignContainerId
,TC.CategoryID AS TestCampaignCategoryId
,TC.Grade
,TC.TestCampaignId
,T.TestSetId
,TL.TestId
,TL.SectionNo
,TL.Difficulty
,TestletName = CHAR(65 + TL.SectionNo) + CONVERT(VARCHAR(4), 6 - TL.Difficulty) -- prevod na A5, B4, B5 ...
,TS.StudentId
,TS.ClassId
,TS.Redizo
,[Version] = 1 -- ?
,TestAdaptationId = TA.id
,TL.guid AS TLGuid
,TS.TimeWindowId
INTO [#FinalResult_Base_1]
FROM (
SELECT *
FROM dbo.[TestSet] [TS] WITH (NOLOCK)
WHERE [TS].[Redizo] NOT IN (999999999, 111111119)
) TS
JOIN (
SELECT *
FROM dbo.[Test] [T] WITH (NOLOCK)
WHERE [T].[TestTypeId] = 1
AND [T].[ProcessedOn] IS NOT NULL
) T ON [T].[TestSetId] = [TS].[guid]
JOIN (
SELECT *
FROM dbo.[Testlet] [TL] WITH (NOLOCK)
WHERE [TL].[ShownOn] IS NOT NULL
) TL ON [TL].[TestId] = [T].[guid]
JOIN (
SELECT *
FROM dbo.[TimeWindow] [TW] WITH (NOLOCK)
WHERE [TW].[IsActive] = 1
) TW ON [TW].[id] = [TS].[TimeWindowId]
JOIN (
SELECT *
FROM dbo.[TestAdaptation] [TA] WITH (NOLOCK)
WHERE [TA].[IsActive] = 1
) TA ON [TA].[id] = [TW].[TestAdaptationId]
JOIN (
SELECT *
FROM dbo.[TestCampaign] [TC] WITH (NOLOCK)
WHERE [TC].[IsActive] = 1
) TC ON [TC].[TestCampaignId] = [TA].[TestCampaignId]
--possible unused join in this query
--JOIN dbo.[TestCampaignContainer] [TCC] WITH (NOLOCK) ON [TCC].[TestCampaignContainerId] = [TC].[TestCampaignContainerId] AND [TCC].[IsActive] = 1
SELECT FR1.TestCampaignContainerId
,FR1.TestCampaignCategoryId
,FR1.Grade
,FR1.TestCampaignId
,FR1.TestSetId
,FR1.TestId
,TSK.CategoryID AS [TaskCategoryId]
,TT.[TestletId]
,FR1.SectionNo
,FR1.Difficulty
,TestletName = CHAR(65 + FR1.SectionNo) + CONVERT(VARCHAR(4), 6 - FR1.Difficulty) -- prevod na A5, B4, B5 ...
,FR1.StudentId
,FR1.ClassId
,FR1.Redizo
,TT.ViewCount
,TT.SpentTime
,[Version] = 1 -- ?
,FR1.TestAdaptationId
,TaskId = TSK.TaskId
,TaskPosition = TT.Position
,AnswerType = TT.TestletAnswerTypeId
,TT.guid AS TTGuid
INTO [#FinalResult_Base_2]
FROM #FinalResult_Base_1 FR1
JOIN [TestTask] [TT] WITH (NOLOCK) ON [TT].[TestletId] = [FR1].[TLGuid]
JOIN [Task] [TSK] WITH (NOLOCK) ON [TSK].[TaskId] = [TT].[TaskId]
--possible unused join
--JOIN [category] [C] WITH (NOLOCK) ON [C].[CategoryID] = [TSK].[CategoryID]
WHERE [TSK].[IsActive] = 1
--AND [C].[IsActive] = 1
DROP TABLE [#FinalResult_Base_1]
CREATE NONCLUSTERED INDEX [#IX_FR_Student_Class]
ON [dbo].[#FinalResult_Base_2] ([StudentId], [ClassId])
INCLUDE ([TTGuid])
TRUNCATE TABLE [dbo].[FinalResult_Base];
INSERT INTO [dbo].[FinalResult_Base]
SELECT FR2.TestCampaignContainerId
,FR2.TestCampaignCategoryId
,FR2.Grade
,FR2.TestCampaignId
,FR2.TestSetId
,FR2.TestId
,FR2.[TaskCategoryId]
,FR2.[TestletId]
,FR2.SectionNo
,FR2.Difficulty
,FR2.TestletName
,TQ.[QuestionId]
,FR2.StudentId
,FR2.ClassId
,RA.SubjectId
,TQ.[QuestionPoints] -- 1+ good, 0 wrong, null no answer
, GoodAnswer =
CASE WHEN ISNULL(TQ.[QuestionPoints], 0) > 0
THEN 1
ELSE 0
END
, WrongAnswer =
CASE
WHEN ISNULL(TQ.[QuestionPoints], 0) = 0
THEN 1
ELSE 0
END
, NoAnswer =
CASE WHEN TQ.[QuestionPoints] IS NULL
THEN 1
ELSE 0
END
,FR2.Redizo
,FR2.ViewCount
,FR2.SpentTime
,TQ.[Position] AS [QuestionPosition]
,RA.SpecialNeeds -- identifikace SVP
,[Version] = 1 -- ?
,FR2.TestAdaptationId
,FR2.TaskId
,FR2.TaskPosition
,QuestionRate = Q.Rate
,TestQuestionId = TQ.guid
,FR2.AnswerType
FROM [#FinalResult_Base_2] FR2
JOIN [TestQuestion] [TQ] WITH (NOLOCK) ON [TQ].[TestTaskId] = [FR2].[TTGuid]
JOIN [Question] [Q] WITH (NOLOCK) ON [Q].[QuestionId] = [TQ].[QuestionId] AND [Q].[IsActive] = 1
JOIN [RoleAssignment] [RA] WITH (NOLOCK) ON [RA].[PersonID] = [FR2].[StudentId]
AND [RA].[ClassId] = [FR2].[ClassId]
AND [RA].[IsActive] = 1
AND [RA].[RoleId] = 1
DROP TABLE #FinalResult_Base_2;

IMHO It should not be the case, I faced similar problem and took the following steps to optimize it.
Try putting Indexes on the columns which are used in filtering (The
columns deciding the joins).
Try to put indexes on Views, It could be done but It needs some
special requirements.
Have some jobs for Index Rebuilding.
Use another mirror instance of DB for reporting leave the live DB
Don't use functions while joining if you want to transform data do it
after joining.
Use Query optimizer to view what part of join is taking most of the
time/resources.
Use an Archive table to purge data into it from live DB.
Hope it helps :)

Related

The stored procedure return Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32)

;WITH #SearchHistory (OrderDetail_ID, RelatedOrderDetail_ID, OrigOrderDetail_ID, TimesRolled) AS
(
SELECT od.OrderDetail_ID
,od.RelatedOrderDetail_ID
,0
,0
FROM #SearchFilter f1
INNER JOIN RLHistory.dbo.TRRawDetail od (NOLOCK)
ON od.ConfirmationNo LIKE f1.OrigConfirmationNo + '%'
AND od.ConfirmationNo <> f1.ConfirmationNo
AND od.ItemType_ID IN (14,27)
UNION ALL
SELECT od.OrderDetail_ID
,od.RelatedOrderDetail_ID
,0
,0
FROM #SearchFilter f1
INNER JOIN RueschLink.dbo.ClientOrder co (NOLOCK)
ON co.ConfirmationNo LIKE f1.OrigConfirmationNo + '%'
AND co.ConfirmationNo <> f1.ConfirmationNo
INNER JOIN RueschLink.dbo.OrderDetail od (NOLOCK)
ON od.ClientOrder_ID = co.ClientOrder_ID
AND od.ItemType_ID IN (14,27)
UNION ALL
SELECT od.OrderDetail_ID
,od.RelatedOrderDetail_ID
,CASE WHEN ISNULL(f2.RelatedOrderDetail_ID, 0) = 0 THEN f2.OrderDetail_ID ELSE f2.OrigOrderDetail_ID END
,f2.TimesRolled + 1 - (CASE WHEN ItemType_ID IN (14,27) THEN 0 ELSE 1 END)
FROM #SearchHistory AS f2
INNER JOIN RueschLink.dbo.OrderDetail od (NOLOCK)
ON od.RelatedOrderDetail_ID = f2.OrderDetail_ID
AND od.ItemType_ID IN (14,27,82,83)
UNION ALL
SELECT od.OrderDetail_ID
,od.RelatedOrderDetail_ID
,CASE WHEN ISNULL(f2.RelatedOrderDetail_ID, 0) = 0 THEN f2.OrderDetail_ID ELSE f2.OrigOrderDetail_ID END
,f2.TimesRolled + 1 - (CASE WHEN ItemType_ID IN (14,27) THEN 0 ELSE 1 END)
FROM #SearchHistory AS f2
INNER JOIN RLHistory.dbo.TRRawDetail od (NOLOCK)
ON od.RelatedOrderDetail_ID = f2.OrderDetail_ID
AND od.ItemType_ID IN (14,27,82,83)
)
-- create the report list and use it to collect more details
INSERT INTO #ReportList
(OrderDetail_ID
,RelatedOrderDetail_ID
,OrigOrderDetail_ID
,ConfirmationNo
,OrigConfirmationNo
,TimesRolled
,Reissue)
SELECT f1.OrderDetail_ID
,f1.RelatedOrderDetail_ID
,MAX(f2.OrigOrderDetail_ID)
,f1.ConfirmationNo
,f1.OrigConfirmationNo
,ISNULL(MAX(f2.TimesRolled), 0)
,CASE WHEN ISNULL(MAX(f2.TimesRolled), 0) > 0 THEN 'Y' ELSE 'N' END
FROM #SearchFilter f1
LEFT JOIN #SearchHistory f2
ON f1.OrderDetail_ID = f2.OrderDetail_ID
GROUP BY f1.ConfirmationNo, f1.OrigConfirmationNo, f1.OrderDetail_ID, f1.RelatedOrderDetail_ID
ORDER BY f1.ConfirmationNo
CREATE TABLE #ReportDetails
(
ClientOrder_ID INT
,ConfirmationNo VARCHAR(17)
,ConfirmationNo1 VARCHAR(100)
,OrigConfirmationNo VARCHAR(17)
,ClientName VARCHAR(90)
,Account VARCHAR(100)
,CurrencyCode VARCHAR(17)
,Amount VARCHAR(30)
,SettlementCurrencyCode VARCHAR(17)
,SettlementAmount VARCHAR(30)
,ItemRate VARCHAR(15)
,NewValueDate DATE
,OrigValueDate DATE
,OrderDate DATE
,OrderType VARCHAR(100)
,BeneficiaryName VARCHAR(140)
,OrderSource VARCHAR(100)
,Enteredby VARCHAR(100)
,Reissue VARCHAR(3) DEFAULT 'N'
,TimesRolled INT
,NumberofDaysRolled INT
,Trader VARCHAR(90)
,Trader_ID INT
,Comment VARCHAR(100)
,OrderDetail_ID INT
,WeightedAverage CHAR(1) DEFAULT ''
,OrigOrderDetail_ID INT
,OptionID Varchar(100)
,OriginalAmount VARCHAR(30)
,NewCloseDate Date
,CompletedTenor varchar(30)
,OriginalBookingDate Date
)
--start building the report
INSERT INTO #ReportDetails
(ClientOrder_ID
,ConfirmationNo
,ConfirmationNo1
,OrigConfirmationNo
,ClientName
,Account
,CurrencyCode
,Amount
,SettlementCurrencyCode
,SettlementAmount
,ItemRate
,NewValueDate
,OrderDate
,OrderType
,BeneficiaryName
,OrderSource
,Enteredby
,Reissue
,TimesRolled
,Trader_ID
,Comment
,OrderDetail_ID
,OrigOrderDetail_ID
,OptionID
,OriginalAmount
,NewCloseDate
,CompletedTenor
,OriginalBookingDate)
SELECT
od.ClientOrder_ID
,rl.ConfirmationNo
,('6' + ',' + ltrim(rtrim(Str(ISNULL(od.OrderDetail_ID, 0)))) + ',' + ltrim(rtrim(Str(ISNULL(od.ClientOrder_ID, 0)))) + ',' + ltrim(rtrim(od.ConfirmationNo)) + ',%' + ltrim(rtrim(od.ItemNo))) --link confirmation no
,rl.OrigConfirmationNo
,c.DESCRIPTION -- ClientName
,UPPER(co.Account) -- Account
,od.CurrencyCode -- CurrencyCode
,LTRIM(STR(od.ForeignAmount, 30, ISNULL(od.ForeignAmt_NDec, 2)))-- Amount
,co.Settlement_SWIFT-- SettlementCurrencyCode
,LTRIM(STR(od.Extension, 30, ISNULL(co.SettlementAmt_NDec, 2))) --Settlement Amount
,LTRIM(STR(od.ItemRate, 15, ISNULL(od.ItemRate_NDec, 2))) -- ItemRate
,COALESCE(trdvd.RequestedValueDate, od.ReleaseDate) -- NewValueDate
,co.Ordered -- OrderDate
,ot.DESCRIPTION -- OrderType
,od.BeneName -- BeneficiaryName
,COALESCE(a.Description, a2.Description, #RepoOrderSource) -- OrderSource
,co.UserName -- Enteredby
,rl.Reissue
,rl.TimesRolled
,COALESCE(qh.updid, qh.User_ID, qh.initid, q.updid, q.User_ID, q.initid, co.initid) -- Trader_ID
,rsr.Instructions
,CASE WHEN od.FundedBy = #FundedByMultiple THEN od.OrderDetail_ID ELSE 0 END
,rl.OrigOrderDetail_ID
,(CASE WHEN co.ordertype_id in (6,45,5,11) THEN odOrg.OptionContractId ELSE NULL END) --new column added for PBR-1192
,(CASE WHEN co.ordertype_id in (6,45,5,11) THEN LTRIM(STR(odOrg.ForeignAmount, 30, ISNULL(odOrg.ForeignAmt_NDec, 2))) ELSE NULL END)--new column added for PBR-1192
,(CASE WHEN co.ordertype_id in (6,45,5,11) THEN od.ReleaseDate + od.WindowLength ELSE null END) --new column added for PBR-1192
,(CASE WHEN co.ordertype_id in (6,45,5,11) THEN DateDiff(day,coOrg.Ordered,(od.ReleaseDate + isnull(od.WindowLength,0))) ELSE NULL END) --new column added for PBR-1192
,(CASE WHEN co.ordertype_id in (6,45,5,11) THEN coOrg.Ordered ELSE NULL END) --new column added for PBR-1192
FROM #ReportList rl
INNER JOIN RLHistory.dbo.TRRawDetail od (NOLOCK) ON rl.OrderDetail_ID = od.OrderDetail_ID
INNER JOIN RLHistory.dbo.TRRawHeader co (NOLOCK) ON co.ClientOrder_ID = od.ClientOrder_ID
INNER JOIN RueschLink.dbo.Client AS c (NOLOCK) ON co.Client_ID = c.Client_ID
INNER JOIN RueschLink.dbo.OrderType AS ot (NOLOCK) ON co.OrderType_ID = ot.OrderType_ID
LEFT OUTER JOIN RueschLink.dbo.Application AS a (NOLOCK) ON (co.Application_ID = a.Application_ID AND a.Application_ID = 3)-- a.Description = #FwdOrderSource)
LEFT OUTER JOIN VMaRS.dbo.RSRepurchase AS rsr (NOLOCK) ON rsr.ClientOrder_ID = od.ClientOrder_ID
LEFT OUTER JOIN RueschLink.dbo.Application AS a2 (NOLOCK) ON a2.Application_ID = rsr.ApplicationID
LEFT OUTER JOIN crs..Quote q (NOLOCK) ON od.Quote_ID = q.Quote_ID
LEFT OUTER JOIN crs..QuoteHistory qh (NOLOCK) ON od.Quote_ID = qh.Quote_ID
LEFT OUTER JOIN RLHistory.dbo.TRRawDetailValueDate AS trdvd (NOLOCK) ON od.OrderDetail_ID = trdvd.OrderDetail_ID
LEFT JOIN RLHistory.dbo.TRRawDetail odOrg (NOLOCK) ON odOrg.OrderDetail_ID=RueschLink.dbo.ReturnParentOrderDetailID (od.RelatedOrderDetail_ID) --Join Added for PBR-1192
AND od.RelatedOrderDetail_ID>0 AND od.RelatedOrderDetail_ID IS NOT NULL
LEFT JOIN RLHistory.dbo.TRRawHeader coOrg (NOLOCK) ON coOrg.ClientOrder_ID = odOrg.ClientOrder_ID --Join Added for PBR-1192
ORDER BY co.ConfirmationNo --order the confirmation number asc

Combining Three Selects into One

I've been trying to consolidate these three SQL functions into one.
Functions
Function 1
`ALTER FUNCTION [dbo].[Fn_Get_User] (#_CompanyKey INT)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE #UserIDs AS VARCHAR(8000);
SET #UserIDs = '';
SELECT #UserIDs = #UserIDs + ', ' + x.User_ID
FROM
(SELECT DISTINCT UPPER(p.User_ID) as User_ID
FROM [dbo].[Program] AS p WITH (NOLOCK)
WHERE p.CompanyKey = #_CompanyKey
UNION
SELECT DISTINCT UPPER(ps.User_ID) as User_ID
FROM [dbo].[Program] AS p WITH (NOLOCK)
LEFT OUTER JOIN [dbo].[Program_Scenario] AS ps WITH (NOLOCK)
ON p.ProgramKey = ps.ProgramKey
WHERE p.CompanyKey = #_CompanyKey
AND ps.User_ID IS NOT NULL) x
RETURN Substring(#UserIDs, 3, 8000);
END`
Function 2
`ALTER FUNCTION [dbo].[Fn_Get_Source] (#_CompanyKey INT)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE #System_IDs AS VARCHAR(8000);
SET #System_IDs = '';
SELECT #System_IDs = #System_IDs + ', ' + Original_Source_System_ID
FROM (
SELECT DISTINCT p.Original_Source_System_ID
FROM [dbo].[Program] AS p WITH (NOLOCK)
WHERE p.CompanyKey = #_CompanyKey
) a
RETURN Substring(#System_IDs, 3, 8000);
END`
Function 3
`ALTER FUNCTION [dbo].[Fn_Get_ContractNbr] (#_CompanyKey INT)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE #ContractNums AS VARCHAR(8000);
SET #ContractNums = '';
SELECT #ContractNums = #ContractNums + ', ' + bi.Contract_Nbr + '-' +
ISNULL(CAST(bi.Year_Nbr AS varchar(8)),'') + '-' +
ISNULL(CAST(bi.Layer_Nbr AS varchar(8)),'')
FROM [dbo].[Program] AS p WITH (NOLOCK)
INNER JOIN [dbo].[Program_Scenario] AS ps WITH (NOLOCK) ON p.ProgramKey = ps.ProgramKey
INNER JOIN [dbo].[Layer] AS l WITH (NOLOCK) ON ps.ProgramScenarioKey = l.ProgramScenarioKey
INNER JOIN [dbo].[Bound_Information] AS bi WITH (NOLOCK) ON l.LayerKey = bi.LayerKey
AND ISNULL(bi.Contract_Nbr,'') <> '' --IS NOT NULL
WHERE p.CompanyKey = #_CompanyKey
RETURN Substring(#ContractNums, 3, 8000);
END`
My attempted Solution
`SET STATISTICS TIME ON
SELECT DISTINCT UPPER((p.User_ID) +', '+ ps.User_ID) as UserID,
bi.Contract_Nbr as ContractNumber,
p.Original_Source_System_ID as SourceSysID,
ISNULL(CAST(bi.Year_Nbr AS varchar(8)),'') as UW_Year,
ISNULL(CAST(bi.Layer_Nbr AS varchar(8)),'') as LayerNumber,
p.CompanyKey,
ps.ProgramKey,
c.Company_Name
FROM
[dbo].[Program] AS p WITH (NOLOCK)
INNER JOIN [dbo].[Program_Scenario] AS ps WITH (NOLOCK)
ON p.ProgramKey = ps.ProgramKey
INNER JOIN [dbo].[Layer] AS l WITH (NOLOCK) ON ps.ProgramScenarioKey = l.ProgramScenarioKey
INNER JOIN [dbo].[Bound_Information] AS bi WITH (NOLOCK) ON l.LayerKey = bi.LayerKey
INNER JOIN [dbo].[Company] AS c with (NOLOCK) ON p.CompanyKey = c.CompanyKey
AND ISNULL(bi.Contract_Nbr,'') <>''
AND ps.User_ID IS NOT NULL
WHERE p.CompanyKey between 2 and 100000
ORDER BY ProgramKey`
My data-set is 20k+ rows so I'm unable to share it here, but where I'm struggling is my function is not returning the same amount of rows as the above three functions. Might there be anything anyone sees to possibly solve this issue? (24755 rows vs. 24052 rows respectively)

Locking From Temp Table - SQL 2008 R2

I have just implemented a new database on our live environment, this database is fed information by a service brokers from our two transactional databases. When the messages come into the new database we have a series of stored procedures which manipulate the feed for each specific user.
I also have another set of stored procedures which re-manipulate the data by user instead of by vehicle, these are used by our maintenance screens to ensure we can change users visibility of the data.
The below stored procedure keeps locking up I have now amended this sp to update a temp table first and then just undertake one update against the main database, however this has not aided the situation, I have also amended so I can update in smaller batches and if this fails keep retrying until it is successful. This works 100% on our dev environment but on live it keeps locking. The throughput on the servicebrokers is not great enough to register the number of failures, I therefore believe I am locking myself within this sp?
I have included ---'THIS UPDATE KEEPS LOCKING' at the point of failure.
What could be causing this locking behavior?
USE [Isight]
GO
/** Object: StoredProcedure [dbo].[UserVisibilityForVehicles] Script Date: 07/18/2014 14:43:04 **/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[UserVisibilityForVehicles]
-- Add the parameters for the stored procedure here
#Username VARCHAR(50)
WITH RECOMPILE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
PRINT 'UserVisibilityForVehicles Started'
-- Now Start to check security for user.
IF EXISTS ( SELECT ID FROM dbo.SecurityTable WHERE userid = #Username AND Deleted = 0)
BEGIN
CREATE TABLE #VehicleToUsers(ID BIGINT, NewRecord BIT DEFAULT(0))
CREATE CLUSTERED INDEX IDX_VehicleToUsers ON #VehicleToUsers(ID)
CREATE NonCLUSTERED INDEX IDX_NewRecord ON #VehicleToUsers(ID)
INSERT INTO #VehicleToUsers
( ID )
(
SELECT Distinct Veh.[ID]
FROM [iSight].[dbo].[Vehicle] Veh WITH (NOLOCK)
INNER JOIN SecurityTable WITH (NOLOCK) ON Veh.[System] = SecurityTable.[System]
WHERE SecurityType = 1 AND UserID = #Username AND SecurityTable.deleted = 0
)
INSERT INTO #VehicleToUsers
( ID )
(
SELECT DISTINCT Veh.[ID]
FROM [iSight].[dbo].[Vehicle] Veh WITH (NOLOCK)
INNER JOIN SecurityTable WITH (NOLOCK) ON Veh.[System] = SecurityTable.[System] AND Veh.CurrentSite = SecurityTable.[Site]
WHERE SecurityType = 2 AND UserID = #Username AND SecurityTable.deleted = 0
)
BEGIN
PRINT 'UserVisibilityForVehicles: ' + #Username
INSERT INTO #VehicleToUsers
( ID )
(
SELECT DISTINCT Vehicle.ID
FROM Manufacturer WITH (NOLOCK) INNER JOIN
ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement INNER JOIN
SecurityTable WITH (NOLOCK) ON Manufacturer.ManufacturerGroupID = SecurityTable.ManufacturerGroupID AND Vehicle.System = SecurityTable.System
WHERE (SecurityTable.SecurityType = 3) AND (SecurityTable.UserID = #Username) AND ManufacturerMake.Deleted = 0 AND ManufacturerAgreementSubcustomer.Deleted = 0 AND SecurityTable.deleted = 0
)
INSERT INTO #VehicleToUsers
( ID )
(
SELECT DISTINCT Vehicle.ID
FROM Manufacturer WITH (NOLOCK) INNER JOIN
ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement INNER JOIN
SecurityTable WITH (NOLOCK) ON Vehicle.System = SecurityTable.System AND Manufacturer.ID = SecurityTable.ManufacturerID
WHERE (SecurityTable.SecurityType = 4) AND (SecurityTable.UserID = #Username) AND ManufacturerMake.Deleted = 0 AND ManufacturerAgreementSubcustomer.Deleted = 0 AND SecurityTable.deleted = 0
)
INSERT INTO #VehicleToUsers
( ID )
(
SELECT DISTINCT Vehicle.ID
FROM Manufacturer WITH (NOLOCK) INNER JOIN
ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement INNER JOIN
SecurityTable WITH (NOLOCK) ON Vehicle.System = SecurityTable.System AND Manufacturer.ID = SecurityTable.ManufacturerID AND
ManufacturerAgreementSubcustomer.ID = SecurityTable.ManufacturerAgreementSub INNER JOIN
ManufacturerUserAgreementSubcustomer WITH (NOLOCK) ON
ManufacturerAgreementSubcustomer.ID = ManufacturerUserAgreementSubcustomer.ManufacturerAgreementSubcustomerID AND
SecurityTable.ManufacturerID = ManufacturerUserAgreementSubcustomer.ManufacturerID AND
SecurityTable.UserID = ManufacturerUserAgreementSubcustomer.UserName
WHERE (SecurityTable.SecurityType = 5) AND (SecurityTable.UserID = #Username) AND (ManufacturerMake.Deleted = 0) AND
(ManufacturerAgreementSubcustomer.Deleted = 0) AND (ManufacturerUserAgreementSubcustomer.Deleted = 0) AND SecurityTable.deleted = 0
)
INSERT INTO #VehicleToUsers
( ID )
(
SELECT DISTINCT Vehicle.ID
FROM Manufacturer WITH (NOLOCK) INNER JOIN
ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement AND
ManufacturerAgreementSubcustomer.Subcustomer = Vehicle.CurrentSubCustomer INNER JOIN
SecurityTable WITH (NOLOCK) ON Vehicle.System = SecurityTable.System AND Manufacturer.ID = SecurityTable.ManufacturerID AND
ManufacturerAgreementSubcustomer.ID = SecurityTable.ManufacturerAgreementSub INNER JOIN
ManufacturerUserAgreementSubcustomer WITH (NOLOCK) ON
ManufacturerAgreementSubcustomer.ID = ManufacturerUserAgreementSubcustomer.ManufacturerAgreementSubcustomerID AND
SecurityTable.UserID = ManufacturerUserAgreementSubcustomer.UserName AND
SecurityTable.ManufacturerID = ManufacturerUserAgreementSubcustomer.ManufacturerID
WHERE (SecurityTable.SecurityType = 6) AND (SecurityTable.UserID = #Username) AND (ManufacturerMake.Deleted = 0) AND
(ManufacturerAgreementSubcustomer.Deleted = 0) AND (ManufacturerUserAgreementSubcustomer.Deleted = 0) AND SecurityTable.deleted = 0
)
END
CREATE TABLE #VehicleToUserCopy(ID BIGINT, vehicleTableID BIGINT, Deleted BIT DEFAULT(1), UpdatedAt DATETIME DEFAULT (GETDATE()), UpdatedBy VARCHAR(50) DEFAULT('UserVisibilityForVehicles-Update'), NextToUpdate BIT DEFAULT(0))
CREATE CLUSTERED INDEX idx_ID ON #VehicleToUserCopy(ID)
CREATE NONCLUSTERED INDEX idx_VehicleTableID ON #VehicleToUserCopy(vehicleTableID)
CREATE NONCLUSTERED INDEX idx_NextToUpdate ON #VehicleToUserCopy(NextToUpdate)
INSERT INTO #VehicleToUserCopy
( ID ,
vehicleTableID ,
Deleted
)
(
SELECT ID, vehicleTableID, Deleted
FROM dbo.VehicleToUser WITH (nolock)
WHERE Username = #Username
)
PRINT 'Starting to do updates'
--Not required as default set to 1
----UPDATE VehicleToUser
----SET DELETED = 1
----,UpdatedAt = GETDATE()
----,UpdatedBy = 'UserVisibilityForVehicles'
----FROM dbo.VehicleToUser WITH (NOLOCK)
----LEFT JOIN #VehicleToUsers AS UsersVehicles ON VehicleToUser.VehicleTableID = UsersVehicles.ID
----WHERE UserName = #Username AND UsersVehicles.ID IS null
PRINT 'Starting to do updates - Set Deleted = 0'
SET LOCK_TIMEOUT 1000 -- set to second
DECLARE #Tries tinyint
UPDATE #VehicleToUserCopy
SET Deleted = 0
FROM #VehicleToUserCopy AS VehicleToUserCopy
inner JOIN #VehicleToUsers AS UsersVehicles ON VehicleToUserCopy.VehicleTableID = UsersVehicles.ID
INSERT INTO VehicleToUser(UserName, VehicleTableID, DELETED, UpdatedAt, UpdatedBy)
(
SELECT DISTINCT #Username, TempVehicle.ID, 0 , GETDATE(), 'UserVisibilityForVehicles-Insert'
FROM #VehicleToUsers AS TempVehicle
LEFT JOIN (
SELECT VehicleTableID
FROM #VehicleToUserCopy WITH (NOLOCK)
) AS [VehicleToUser] ON TempVehicle.ID = [VehicleToUser].VehicleTableID
WHERE [VehicleToUser].VehicleTableID IS null
)
DECLARE #ID bigint
SELECT #ID = ID FROM #VehicleToUserCopy
WHILE ##rowcount > 0
BEGIN
SET ROWCOUNT 1000
SELECT #Tries = 1
WHILE #Tries <= 3
BEGIN
BEGIN TRANSACTION
BEGIN TRY
UPDATE #VehicleToUserCopy SET NextToUpdate = 1
---'THIS UPDATE KEEPS LOCKING'
UPDATE dbo.VehicleToUser
SET Deleted = VehicleToUserCopy.Deleted
, UpdatedAt = GETDATE()
, UpdatedBy = VehicleToUserCopy.UpdatedBy
FROM VehicleToUser
inner JOIN #VehicleToUserCopy AS VehicleToUserCopy ON VehicleToUser.ID = VehicleToUserCopy.ID
WHERE VehicleToUserCopy.NextToUpdate = 1
PRINT 'WORKED'
DELETE FROM #VehicleToUserCopy WHERE NextToUpdate = 1
COMMIT
-- therefore we can leave our loop
BREAK
END TRY
BEGIN CATCH
ROLLBACK --always rollback
PRINT 'Rolled Back '
-- Now check for Blocking errors 1222 or Deadlocks 1205 and if its a deadlock wait for a while to see if that helps
SELECT ERROR_MESSAGE()
IF ERROR_NUMBER() = 1205 OR ERROR_NUMBER() = 1222
BEGIN
-- if its a deadlock wait 2 seconds then try again
IF ERROR_NUMBER() = 1205
BEGIN -- wait 2 seconds to see if that helps the deadlock
WAITFOR DELAY '00:00:02'
END
-- no need to wait for anything for BLOCKING ERRORS as our LOCK_TIMEOUT is going to wait for half a second anyway
-- and if it hasn't finished by then (500ms x 3 attempts = 1.5 seconds) there is no point waiting any longer
END
SELECT #Tries = #Tries + 1 -- increment and try again for 3 goes
-- we carry on until we reach our limit i.e 3 attempts
CONTINUE
END CATCH
END
SELECT #ID = ID FROM #VehicleToUserCopy
End
SET ROWCOUNT 0
DROP TABLE #VehicleToUsers
END
ELSE
BEGIN
DELETE FROM dbo.VehicleToUser WHERE username = #Username
DELETE FROM dbo.VehicleToUser_UserCurrentImageCount WHERE username = #Username
DELETE FROM dbo.VehicleToUser_UsersCurrentVehicles WHERE username = #Username
End
Try changing your update slightly. I have seen some inconsistent results when using an update like this and you update the base table. You should instead update the alias.
UPDATE v
SET Deleted = VCopy.Deleted
, UpdatedAt = GETDATE()
, UpdatedBy = VCopy.UpdatedBy
FROM VehicleToUser v
inner JOIN #VehicleToUserCopy AS VCopy ON v.ID = VCopy.ID
WHERE VCopy.NextToUpdate = 1

Execution of sql query takes a long time

I have this problem with my query that it is really slow. I am using MSSQL server 2008 and have 3 DB with hundreds of sample data in it. The query will return a name and value and a computed percentage based on the 3 DBs. But the query I have will take almost 10mins to execute which is really a long time to take. I am still learning SQL and still not that good so I think the query I have is not using the best practice and not organized. Can anybody point to me where or how I can improve my query to run faster?
SELECT data.Ret,
case
when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5') and (data.rowid % 50) = 0 then (data.rowid / 50)-1
when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5') then (data.rowid / 50)
else 0 end as batchStore
,data.MajorName,data.MinorName,data.MajorVal,data.MinorVal,data.Version
,data.A_Percent,data.T_Percent,data.F_Percent
from
(
SELECT report.Ret,
CASE when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5')
then row_number() over (PARTITION BY report.Ret,report.Version order by report.Ret, report.MajorName)
else 0 end as rowid
,report.MajorName,report.MinorName,report.MajorVal,report.MinorVal,report.Version
,report.GTotal_A,report.GTotal_T,report.GTotal_F
,ISNULL(sum(report.Abn) / NULLIF(cast(report.GTotal_A as decimal),0),0) * 100 as A_Percent
,ISNULL(sum(report.Trn) / NULLIF(cast(report.GTotal_T as decimal),0),0) * 100 as T_Percent
,ISNULL(sum(report.Fld)/ NULLIF(cast(report.GTotal_F as decimal),0) * 100,0) as F_Percent
From
(
Select
CASE #group_by
WHEN 'object' THEN csl.s_name
WHEN 'site' THEN csl.s_name
WHEN 'year' THEN CAST(YEAR(dy.Day_Stamp) AS VARCHAR(50))
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeName,'') AS VARCHAR(50))
ELSE ''
END as MajorName,
CASE #group_by
WHEN 'object' THEN l.l_name
WHEN 'site' THEN ''
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeName,'') AS VARCHAR(50))
ELSE ''
END as MinorName,
CASE #group_by
WHEN 'object' THEN csl.s_name
WHEN 'site' THEN csl.s_name
WHEN 'year' THEN CAST(YEAR(dy.Day_Stamp) AS VARCHAR(50))
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeValue,'') AS VARCHAR(50))
ELSE ''
END as MajorVal,
CASE #group_by
WHEN 'object' THEN l.l_name
WHEN 'site' THEN ''
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeValue,'') AS VARCHAR(50))
ELSE ''
END as MinorVal,
csl.Cust_Name as Ret,l.SWVersion as Version
,d.Abn,d.Trn,d.Fld,data.GTotal_A ,data.GTotal_T,data.GTotal_F
From db_mon.dbo.CustSL csl
join db_tax.dbo.vwLane l
on (l.externalid = csl.custsl_id)
join db_mon.dbo.DaySummary dy
on (dy.Str = csl.s_name and dy.Lne = csl.l_name and year(dy.day_stamp) = year(#time_start_date) and year(dy.day_stamp) =year(#time_end_date))
Left Outer Join
(
Select a.id As AttributeId, a.attribute_name As AttributeName,
(Case When a.attribute_value_type = 'string' Then ea.string_value
Else (Case When a.attribute_value_type = 'integer' Then cast(ea.integer_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'date' Then cast(ea.date_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'boolean' Then cast(ea.boolean_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'entity' Then cast(ea.ref_entity_id as nvarchar(100)) Else null End)
End)
End)
End)
End) As AttributeValue,
e.id As EntityId
From db_tax.dbo.entity_type et
Inner Join db_tax.dbo.entity As e on et.id = e.entity_type_id
Inner Join db_tax.dbo.entity_attribute As ea on e.id = ea.entity_id
Inner Join db_tax.dbo.attribute As a on ea.attribute_id = a.id
WHERE et.entity_type_name in ('Sticker','Label') And
a.id = (case WHEN #attribute_id = '' then 1 else cast(#attribute_id as int) end)
) AS attrib
On attrib.EntityId = l.L_Id
inner join db_mon.dbo.DaySummary d
on (csl.Cust_Name = d.Ret and csl.s_name = d.stckr and csl.l_name = d.label and l.SWVersion = d.Version)
join (
SELECT Ret,version,sum(Abn) as GTotal_A,sum(Trn) as GTotal_T,sum(Fld) as GTotal_F
from db_mon.dbo.DaySummary
where day_stamp >= #time_start_date and day_stamp <=#time_end_date
GROUP BY Ret,version
) data
on (d.Ret = data.Ret and l.SWVersion = data.Version)
WHERE (CHARINDEX(',' + CONVERT(VARCHAR,l.S_Id) + ',','xxx,' + #entities + ',xxx')>0 OR CHARINDEX(',' + CONVERT(VARCHAR,l.L_Id) + ',','xxx,' + #entities + ',xxx')>0)
and d.day_stamp >= #time_start_date
and d.day_stamp <=#time_end_date
) As report
Group By report.Ret,report.Version,report.MajorName,report.MinorName,report.MajorVal,report.MinorVal
,report.GTotal_A,report.GTotal_T,report.GTotal_F
)data
order By data.Ret,data.Version,batchStore,data.MajorName,data.MinorName,data.MajorVal,data.MinorVal
Does using a lot of join causes the slow execution?
SUB Select queries will always be slower then proper joins.
You are running 3 sub selects deep. This is going to impact your performance regardless of changing indexes etc.
You need to rewrite the whole thing to stop using sub selects.

SQL Server 2008 - Update SQL Help Needed

First and foremost, the SQL is handled dynamically by the server, therefore some items in my WHERE clause may look odd to you, please disregard these as they are not an issue.
Per my clients request, they needed to UNION in two other conditions to my update report (/Patients without a Patient Visit/) and (/Patients without a Appointment/). I need help adding in the patients of these two subsets into my final update query. In its present state, it's only adding in the #Temp patients and I need to incorporate the additional patients.
Any help is GREATLY appreciated.
My current SQL update -
DECLARE #Inactive INT
DECLARE #Active INT
DECLARE #PatientProfileId INT
SELECT
#Inactive = MedlistsId
FROM
Medlists
WHERE
TableName = 'PatientProfileStatus'
AND Code = 'I'
SELECT
#Active = MedlistsId
FROM
Medlists
WHERE
TableName = 'PatientProfileStatus'
AND Code = 'A'
CREATE TABLE #Temp
(
PatientName VARCHAR(120) ,
PatientProfileId INT ,
RecentId INT ,
Recent DATETIME
)
INSERT INTO #Temp
SELECT
dbo.FormatName(pp.Prefix , pp.First , pp.Middle , pp.Last , pp.Suffix) AS Name ,
pp.PatientProfileId ,
MAX(pv.PatientVisitId) AS RecentId ,
MAX(pv.Visit) AS Recent
FROM
PatientVisit pv
INNER JOIN PatientProfile pp ON pv.PatientProfileId = pp.PatientProfileId
AND pp.PatientStatusMId = #Active
WHERE
pp.PatientProfileId IN ( SELECT
a.OwnerId
FROM
Appointments a
INNER JOIN PatientProfile pp ON a.OwnerId = pp.PatientProfileId
AND a.ApptKind = 1
AND pp.PatientStatusMId = #Active
GROUP BY
a.OwnerId ,
a.ApptKind
HAVING
MAX(a.ApptStart) < '07/30/2005' )
GROUP BY
dbo.FormatName(pp.Prefix , pp.First , pp.Middle , pp.Last , pp.Suffix) ,
pp.PatientProfileId
HAVING
MAX(pv.Visit) < '07/30/2005'
/*Patients without a Appointment*/
IF 1 = 1
INSERT INTO #Temp
SELECT
dbo.FormatName(pp.Prefix , pp.First , pp.Middle , pp.Last , pp.Suffix) AS Name ,
pp.PatientProfileId ,
NULL AS RecentId ,
NULL AS Recent
FROM
PatientProfile pp
LEFT JOIN ( SELECT * FROM Medlists WHERE TableName = 'PatientProfileStatus' ) ml1 ON pp.PatientStatusMId = ml1.MedlistsId
LEFT JOIN Appointments a ON a.Ownerid = pp.PatientProfileId
AND a.ApptKind = 1
LEFT JOIN PatientVisit pv ON a.PatientVisitId = pv.PatientVisitId
WHERE
ml1.Code = 'A'
AND a.ownerid IS NULL
AND --Filter on Age
(
((
'-1' = '-1'
AND '40' = '125'
)
OR ( CAST(( DATEDIFF(DAY , pp.Birthdate , GETDATE()) / 365.25 ) AS INT) BETWEEN ( '-1' ) AND ( '40' ) ))
)
/*Patients without a Patient Visit*/
IF 0 = 1
INSERT INTO #Temp
SELECT
dbo.FormatName(pp.Prefix , pp.First , pp.Middle , pp.Last , pp.Suffix) AS Name ,
pp.PatientProfileId ,
NULL AS RecentId ,
NULL AS Recent
FROM
PatientProfile pp
LEFT JOIN PatientVisit pv ON pv.PatientProfileid = pp.PatientProfileid
LEFT JOIN ( SELECT * FROM Medlists WHERE TableName = 'PatientProfileStatus' ) ml1 ON pp.PatientStatusMId = ml1.MedlistsId
WHERE
ml1.Code = 'A'
AND pv.patientprofileid IS NULL
AND --Filter on Age
(
((
'-1' = '-1'
AND '40' = '125'
)
OR ( CAST(( DATEDIFF(DAY , pp.Birthdate , GETDATE()) / 365.25 ) AS INT) BETWEEN ( '-1' ) AND ( '40' ) ))
)
DECLARE curPatient CURSOR FORWARD_ONLY READ_ONLY LOCAL
FOR
SELECT
t.PatientProfileId
FROM
#Temp t
JOIN PatientProfile pp ON t.PatientProfileId = pp.PatientProfileId
JOIN PatientVisit pv ON pp.PatientProfileId = pv.PatientProfileId
AND pv.PatientVisitId = t.RecentId
WHERE
--Filter on Age
(
((
'-1' = '-1'
AND '40' = '125'
)
OR ( CAST(( DATEDIFF(DAY , pp.Birthdate , GETDATE()) / 365.25 ) AS INT) BETWEEN ( '-1' ) AND ( '40' ) ))
)
OPEN curPatient
FETCH NEXT FROM curPatient INTO #PatientProfileId
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE
PatientProfile
SET
PatientStatusMId = #Inactive ,
pstatus = 'I'
FROM
PatientProfile P
INNER JOIN #Temp t ON t.PatientProfileID = P.PatientProfileID
WHERE
p.PatientProfileId = #PatientProfileId
FETCH NEXT FROM curPatient INTO #PatientProfileId
END
CLOSE curPatient
DEALLOCATE curPatient
DROP TABLE #Temp
This will limit to patients WITH an appointment
LEFT JOIN Appointments a
ON a.Ownerid = pp.PatientProfileId
AND a.ApptKind = 1
This will limit to patients WITH a Visit
LEFT JOIN PatientVisit pv
ON pv.PatientProfileid = pp.PatientProfileid
Try
LEFT OUTER JOIN Appointments a
ON a.Ownerid = pp.PatientProfileId
AND a.ApptKind = 1
Where a.Ownerid is null
LEFT OUTER JOIN PatientVisit pv
ON pv.PatientProfileid = pp.PatientProfileid
Where pv.PatientProfileid is null