MSSQL stored procedure - Timeout expired - sql-server-2008
We have a Web Api service for report building. This service uses MS SQL 2008 database as a data source. The data base works as a mirror in readonly mode.
The service and the database are hosted on different computers of a single local net.
There is a stored procedure in the database named TicketSaleByAggregator, that selects report data. Sometimes the procedure throws following exception:
System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out
Then the procedure is throwing this exception again and again until we recompile it:: ALTER PROCEDURE [dbo] [TicketSaleByAggregator].
After the command ALTER PROCEDURE, the procedure runs perfectly even on big data sets, but after about 10-15 hours the error throws again: Timeout expired
The procedure parameters:
DECLARE #PeriodFrom DATETIME = '2016-12-30 00:00:00'
DECLARE #PeriodTo DATETIME = '2016-12-30 23:59:59'
DECLARE #Dealers Identities
DECLARE #Branches Identities
DECLARE #SaleChannels Identities
DECLARE #Carriers Identities
INSERT INTO #Dealers (Id) VALUES(10068)
INSERT INTO #Branches(Id) VALUES(1),(2),(3)
INSERT INTO #SaleChannels(Id)VALUES (7)
exec TicketSaleByAggregator #PeriodFrom, #PeriodTo, #Dealers, #Branches, #SaleChannels, #Carriers
If we call the procedure locally (on the machine where it is hosted) in SQL Management Studio, then it executes for 15 seconds
If we call the procedure on the machine where the web api service is hosted, in SQL Management Studio, then it executes for 15-16 seconds
.The Result data contains 82540 records
Code of stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[TicketSaleByAggregator]
(
#PeriodFrom DATETIME,
#PeriodTo DATETIME,
#Dealers Identities READONLY,
#Branches Identities READONLY,
#SaleChannels Identities READONLY,
#Carriers Identities READONLY
)
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET NOCOUNT ON
;WITH ParentDealer(childId, parentId, BIN)
AS(
SELECT d.Id,
parentDealer.pId,
parentDealer.BIN
FROM Dealer AS d
JOIN (
SELECT d.Id,
parentDealer.Id pId,
parentDealer.BIN
FROM Dealer d
JOIN Dealer parentDealer
ON parentDealer.Hid = d.Hid.GetAncestor(d.[Hid].[GetLevel]() -1)
) parentDealer
ON d.Id = parentDealer.Id
),
CarrierNames
AS(
SELECT c.Name AS CarrierName
FROM Carrier AS c
INNER JOIN #Carriers crs ON c.Id = crs.Id
),
Result
AS(
SELECT *
FROM
(
SELECT t.[ExpressId] AS TicketExpressId,
o.[OrderCreateDate] AS OperationDate,
1 AS TicketCount,
t.[Tariff] AS Tariff,
6 AS OperationTypeId,
sc.Name AS SalesChannelName,
b.ShortName AS BranchName,
o.CarrierName,
o.PaymentType AS PaymentType,
--financial dealers
uDealer.Surname AS FinancialDealerSurname,
uDealer.Name AS FinancialDealerName,
uDealer.Middlename AS FinancialDealerPatronymic,
d.BIN AS FinancialDealerBin,
uparentDealer.Surname AS FinancialParentDealerSurname,
uparentDealer.Name AS FinancialParentDealerName,
uparentDealer.Middlename AS FinancialParentDealerPatronymic,
parentDealer.BIN AS FinancialParentDealerBin,
--place dealers
uDealer.Surname AS PlaceDealerSurname,
uDealer.Name AS PlaceDealerName,
uDealer.Middlename AS PlaceDealerPatronymic,
d.BIN AS PlaceDealerBin,
uparentDealer.Surname AS PlaceParentDealerSurname,
uparentDealer.Name AS PlaceParentDealerName,
uparentDealer.Middlename AS PlaceParentDealerPatronymic,
parentDealer.BIN AS PlaceParentDealerBin
FROM Ticket AS t
INNER JOIN [Order] AS o ON o.Id = t.OrderId AND o.OrderCreateDate BETWEEN #PeriodFrom AND #PeriodTo
INNER JOIN [Terminal] AS ter ON t.[TerminalId] = ter.[Id]
LEFT JOIN [TerminalData] AS td ON ter.[Id] = td.[Id]
INNER JOIN [SalePoint] AS sp ON td.[SalePointId] = sp.[Id]
INNER JOIN FinAccStation AS fas ON fas.Id = sp.FinAccStationId
INNER JOIN Guo AS g ON g.Id = fas.GuoId
INNER JOIN Department AS dep ON dep.Id = g.DepartmentId
INNER JOIN Dealer AS d ON d.Id = ter.DealerId
INNER JOIN [User] AS uDealer ON uDealer.Id = d.Id
INNER JOIN SalesChannel AS sc ON sc.Id = d.SalesChannelId AND (EXISTS(SELECT * FROM #SaleChannels) AND (d.SalesChannelId IN (SELECT * FROM #saleChannels)) OR NOT EXISTS(SELECT * FROM #saleChannels))
INNER JOIN Branch AS b ON b.Id = dep.BranchId AND (EXISTS(SELECT * FROM #Branches) AND (b.Id IN (SELECT * FROM #Branches)))
INNER JOIN ParentDealer AS parentDealer ON parentDealer.childId = d.Id AND (parentDealer.parentId IN (SELECT Id FROM #Dealers) OR NOT EXISTS(SELECT * FROM #Dealers))
INNER JOIN [User] AS uParentDealer ON uParentDealer.Id = parentDealer.parentId
WHERE t.TicketStatusId IN (3, 6) AND
((EXISTS(SELECT TOP 1 * FROM #Carriers) AND (o.CarrierName IN (SELECT CarrierName FROM CarrierNames))) OR NOT EXISTS(SELECT TOP 1 * FROM #Carriers))
UNION ALL
SELECT t.[ExpressId] AS TicketExpressId,
c.OperationDate AS OperationDate,
-1 AS TicketCount,
(-1)*ct.RetTariff AS Tariff,
3 AS OperationTypeId,
sc.Name AS SalesChannelName,
b.ShortName AS BranchName,
o.CarrierName,
c.PaymentType AS PaymentType,
--financial dealers
uDealer.Surname AS DealerSurname,
uDealer.Name AS DealerName,
uDealer.Middlename AS DealerPatronymic,
d.BIN AS DealerBin,
uparentDealer.Surname AS ParentDealerSurname,
uparentDealer.Name AS ParentDealerName,
uparentDealer.Middlename AS ParentDealerPatronymic,
parentDealer.BIN AS ParentDealerBin,
--place dealers
uDealer1.Surname AS PlaceDealerSurname,
uDealer1.Name AS PlaceDealerName,
uDealer1.Middlename AS PlaceDealerPatronymic,
d1.BIN AS PlaceDealerBin,
uparentDealer1.Surname AS PlaceParentDealerSurname,
uparentDealer1.Name AS PlaceParentDealerName,
uparentDealer1.Middlename AS PlaceParentDealerPatronymic,
parentDealer1.BIN AS PlaceParentDealerBin
FROM Cancelation AS c
INNER JOIN CancelationTicket AS ct ON ct.CancelationId = c.Id
INNER JOIN Ticket AS t ON t.Id = ct.TicketId
INNER JOIN [Order] AS o ON o.Id = c.OrderId
INNER JOIN Terminal AS ter ON ter.Id = IIF(o.PaymentType = 1, c.TerminalId, t.TerminalId)
INNER JOIN Terminal AS ter1 ON ter1.Id = c.TerminalId
LEFT JOIN [TerminalData] AS td ON td.[Id] = ter.Id
INNER JOIN [SalePoint] AS sp ON td.[SalePointId] = sp.[Id]
INNER JOIN FinAccStation AS fas ON fas.Id = sp.FinAccStationId
INNER JOIN Guo AS g ON g.Id = fas.GuoId
INNER JOIN Department AS dep ON dep.Id = g.DepartmentId
INNER JOIN Dealer AS d ON d.Id = ter.DealerId
INNER JOIN Dealer AS d1 ON d1.Id = ter1.DealerId
INNER JOIN [User] AS uDealer ON uDealer.Id = d.Id
INNER JOIN [User] AS uDealer1 ON uDealer1.Id = d1.Id
INNER JOIN SalesChannel AS sc ON sc.Id = d.SalesChannelId AND (EXISTS(SELECT * FROM #SaleChannels) AND (d.SalesChannelId IN (SELECT * FROM #saleChannels)) OR NOT EXISTS(SELECT * FROM #saleChannels))
INNER JOIN Branch AS b ON b.Id = dep.BranchId AND (EXISTS(SELECT * FROM #Branches) AND (b.Id IN (SELECT * FROM #Branches)))
INNER JOIN ParentDealer AS parentDealer ON parentDealer.childId = d.Id AND (parentDealer.parentId IN (SELECT Id FROM #Dealers) OR NOT EXISTS(SELECT * FROM #Dealers))
INNER JOIN [User] AS uParentDealer ON uParentDealer.Id = parentDealer.parentId
INNER JOIN ParentDealer AS parentDealer1 ON parentDealer1.childId = d1.Id
INNER JOIN [User] AS uParentDealer1 ON uParentDealer1.Id = parentDealer1.parentId
WHERE c.OperationDate BETWEEN #PeriodFrom AND #PeriodTo AND
((EXISTS(SELECT TOP 1 * FROM #Carriers) AND (o.CarrierName IN (SELECT CarrierName FROM CarrierNames))) OR NOT EXISTS(SELECT TOP 1 * FROM #Carriers)) AND
c.ResponseXml.value('(/GtETicket_Response/#Type)[1]','nvarchar(max)') != 'ExpressStatus'
)T
)
SELECT *
from Result
END
UPDATED: Code on C# side:
public IEnumerable<RegisterTicketsByDealerReportItem> GetRegisterTicketsByDealerReport(DateTime periodFrom, DateTime periodTo, int[] dealerIds, int[] salesChannelIds, int[] branchIds, int[] carrierIds)
{
var pars = new DynamicParameters();
var identityFailureValue = new { Id = 0 }.ToEmptyTable().AsTableValuedParameter("Identities");
pars.AddDynamicParams(
new
{
PeriodFrom = periodFrom,
PeriodTo = periodTo,
Dealers = dealerIds.Return(ds => ds.Select(d => new { Id = d }).ToDataTable().AsTableValuedParameter("Identities"), identityFailureValue),
Branches = branchIds.Return(br => br.Select(b => new { Id = b }).ToDataTable().AsTableValuedParameter("Identities"), identityFailureValue),
SaleChannels = salesChannelIds.Return(scs => scs.Select(sc => new { Id = sc }).ToDataTable().AsTableValuedParameter("Identities"), identityFailureValue),
Carriers = carrierIds.Return(scs => scs.Select(sc => new { Id = sc }).ToDataTable().AsTableValuedParameter("Identities"), identityFailureValue)
});
var result = Connection.Query<RegisterTicketsByDealerReportItem>("TicketSaleByAggregator", pars,
commandType: CommandType.StoredProcedure,
commandTimeout: dbConfiguration.SqlLargeTimeoutSeconds);
Connection.CloseIfNoTransaction();
return result;
}
Sql connection parametrs:
<add key="SqlLargeTimeoutSeconds" value="00:02:00" />
<add name="Readonly" providerName="System.Data.SqlClient" connectionString="Data Source=.;Initial Catalog=db_Readonly;Integrated Security=True;" />
1- Try to use with(nolock) if it is non sensitive transnational data
2- Stop mirroring and check the speed. mirroring may cause this problem
Related
Use of CTE (WITH) in a MYSQL stored procedure
I'm trying to use CTE for running the query below to avoid the "can't reopen the table xxxx' error in a MySQL stored procedure. MySQL Workbench claims a syntax error and doesn't allow to save the procedure. WITH is underlined in red and reads "With" is not valid a this position for this server version (8.0.13), expecting : CACHE, CHECKSUM, COMMIT..... ELSE -- Board charges WITH cte AS (SELECT id FROM billablehorses) INSERT INTO billablehorses (id, horse, agrid, dos, months, installment, totalamount, billed, payableid) SELECT ah.id, h.name, a.id, ah.dos, TIMESTAMPDIFF(MONTH, ah.dos, b.boardingdate) Months, p.amount, a.totalamount, TRUE, p.id FROM horses h INNER JOIN agreementhorses ah ON h.id = ah.horseid INNER JOIN agreements a ON ah.agreementid = a.id INNER JOIN payables p ON ah.id = p.agreementhorseid INNER JOIN boarding b ON p.ticketid = b.id WHERE p.typeid = 1 AND ah.id IN (SELECT id FROM cte) AND EXISTS (SELECT id FROM billed WHERE id = ah.id); SET msg = CONCAT(ROW_COUNT() , " ", 'board charges inserted'); END IF;
how understand the relation between parent query and subquery in mysql?
Someone please explain the difference between parent query and sub query? How do I understand? e.g: SELECT ra.ID id, ra.ACCOUNT_ID accountId, ef.REAL_NAME realName, a.MOBILE mobile, sps.`NAME` siteName, ef.CREATE_TIME createTime, a.`STATUS` status, ra.`STATUS` siteStatus, ( SELECT aif.APPROVER_NAME FROM audit_info aif WHERE aif.TARGET_ID = a.ID AND af.AUDIT_TYPE=2 AND aif.CREATE_TIME = ( SELECT MAX(af.CREATE_TIME) FROM audit_info af WHERE af.TARGET_ID = a.ID AND af.AUDIT_TYPE=2 ) ) AS approverName FROM account a INNER JOIN site_relation_account ra ON ra.ACCOUNT_ID = a.ID INNER JOIN account_ext ef ON ra.ACCOUNT_ID = ef.ACCOUNT_ID INNER JOIN service_provider_site sps ON sps.ID = ra.SITE_ID LEFT JOIN audit_info af ON af.TARGET_ID = ef.ACCOUNT_ID WHERE ra.ACCOUNT_TYPE = 2
Second query in a set not returning results
Can anyone see any reason why the second result set here produces 0 results even though if I run the queries independently the second one will return results?? SELECT GROUP_CONCAT(DISTINCT(mu.ID)) AS users FROM `companies` c JOIN `companysites` cs ON c.ID = cs.companyID JOIN `users` mu ON cs.ID = mu.siteID JOIN `targetcategories` tcat ON c.smTargetCategory = tcat.ID WHERE isVendor = 0; SET #in = "users"; SELECT * FROM privileges WHERE userID IN (#in); I actually need the 2nd query to be a delete query but want to check results before I do it.
Pass your first query in a sub-query, for delete: DELETE FROM privileges WHERE userID IN ( SELECT GROUP_CONCAT(DISTINCT(mu.ID)) AS userID FROM `companies` c JOIN `companysites` cs ON c.ID = cs.companyID JOIN `users` mu ON cs.ID = mu.siteID JOIN `targetcategories` tcat ON c.smTargetCategory = tcat.ID WHERE isVendor = 0 ); If mysql return error, you can try to 'encapsulate' your subquery: DELETE p.* FROM privileges p WHERE userID IN ( SELECT userID FROM (SELECT GROUP_CONCAT(DISTINCT(mu.ID)) AS userID FROM `companies` c JOIN `companysites` cs ON c.ID = cs.companyID JOIN `users` mu ON cs.ID = mu.siteID JOIN `targetcategories` tcat ON c.smTargetCategory = tcat.ID WHERE isVendor = 0) x);
MySQL Stored Procedure Dupplication Issue
I hope someone can help. I have created this stored procedure to pull some infromation from different tables and when i tun it I get many duplicates, I was wondering if there was a way of sorting it? use ICA if exists( select * from INFORMATION_SCHEMA.ROUTINES where SPECIFIC_SCHEMA = N'ICASchema' and SPECIFIC_NAME = N'candidateOffer' ) drop procedure ICASchema.candidateOffer go create procedure ICASchema.candidateOffer #candidateID INT as begin select c.CandidateID,c.CandidateName, ca.CourseID, co.CourseName, o.OfferID, ot.OfferTypePoints from [ICASchema].[tblCandidate] c join [ICASchema].[tblCandidateOffer] o on c.CandidateID = o.CandidateID join [ICASchema].[tblOffer] ot on o.offerID = ot.OfferType join [ICASchema].[tblCandidateApplication] ca on ca.CourseID = ca.CourseID join [ICASchema].[tblCourse] co on co.CourseName = co.CourseName where c.CandidateID = #candidateID --ORDER BY co.CourseName GROUP BY co.CourseName, c.CandidateID,c.CandidateName, ca.CourseID, o.OfferID, ot.OfferTypePoints end go Thanks Graham
Following example is for creating a simple Proc_GetAllUsers stored procedure. This will solve your duplication issue. DROP PROCEDURE IF EXISTS Proc_GetAllUsers GO CREATE PROCEDURE Proc_GetAllUsers( ) BEGIN -- your sql queries select * FROM users; END Go
try this: select * from (select distinct c.CandidateID,c.CandidateName, ca.CourseID, co.CourseName, o.OfferID, ot.OfferTypePoints from [ICASchema].[tblCandidate] c join [ICASchema].[tblCandidateOffer] o on c.CandidateID = o.CandidateID join [ICASchema].[tblOffer] ot on o.offerID = ot.OfferType join [ICASchema].[tblCandidateApplication] ca on ca.CourseID = ca.CourseID join [ICASchema].[tblCourse] co on co.CourseName = co.CourseName where c.CandidateID = #candidateID GROUP BY co.CourseName, c.CandidateID,c.CandidateName, ca.CourseID, o.OfferID, ot.OfferTypePoints) tablealias order by CourseName
This was the working solution. [code]SELECT c.CandidateID, c.CandidateName, ICASchema.tblOffer.OfferTypePoints, ICASchema.tblCourse.CourseName FROM ICASchema.tblCandidate AS c INNER JOIN ICASchema.tblCandidateOffer ON c.CandidateID = ICASchema.tblCandidateOffer.CandidateID INNER JOIN ICASchema.tblOffer ON ICASchema.tblCandidateOffer.CandidateOfferID = ICASchema.tblOffer.OfferID INNER JOIN ICASchema.tblCourse ON ICASchema.tblOffer.OfferID = ICASchema.tblCourse.OfferTypeID WHERE (c.CandidateID = '3') [/code]
SQL calculating time between assignments
I have to write an SQL statement which contain a field that contain two different values consecutively but in the way I have wrote it, it return always null because it is interpreted as having the two value in the same time! My conditions should be : (ci.field = 'Group' and ci.oldString = 'Triage' ) and (ci.field='assignee' and ci.newString is not NULL) That means calculate time between: when the issue is assigned to group named Triage and when the issue is assigned to a person. How can I fix it? My SQL statement: select TIMEDIFF(a.created,b.created) from (select g.created, g.issueid as groupid1 from changegroup g join changeitem ci on (ci.groupid = g.id) join jiraissue ji on (ji.id = g.issueid) join project p on (p.id = ji.project) join priority pr on (pr.id = ji.priority) where ci.field = 'Group' and ci.oldString = 'Triage' and ci.field='assignee' and ci.newString is not NULL and p.pname = 'Test' and pr.pname='P1' and ji.created between '2011-08-11 14:01:00' and '2011-08-12 14:11:00' ) a left join ( select ji.created, ji.id as groupid2 from jiraissue ji join changegroup g on (g.issueid = ji.id) join project p on (p.id = ji.project) where p.pname = 'Test' and ji.created between '2011-08-11 14:01:00' and '2011-08-12 14:11:00' ) b ON (a.groupid1 = b.groupid2); This is the table from which I should retrieve data
See my comment about the quality of your question but a hint at how to solve this goes like (assuming you can make sure this doesn't create 1-n joins) select groupid_orsomething_else, TIMEDIFF(a.created, b.created) from yourtable left join (select groupid_orsomething_else, created from yourtable where field = 'Group' and oldstring is 'Triage' ) a on a.groupid_orsomething_else = yourtable.groupid_orsomething_else left join (select groupid_orsomething_else, created from yourtable where field = 'assignee' and oldstring is null) b on b.groupid_orsomething_else = yourtable.groupid_orsomething_else