SQL查询非常昂贵
我在SQL Server中有一个查询,它搜索可用的服务提供商来预订约会,如下所示: 我有一个与服务表相关的多对一服务提供商 此外,服务提供商还与员工表中的多对一相关 服务表与StaffMemberService表中的staffMember多对多相关 我有许多与staffMember表相关的任命详情表 您可以在此图中看到详细信息: 查询哪些服务有开放的时间段是非常昂贵的SQL查询非常昂贵,sql,sql-server,search,Sql,Sql Server,Search,我在SQL Server中有一个查询,它搜索可用的服务提供商来预订约会,如下所示: 我有一个与服务表相关的多对一服务提供商 此外,服务提供商还与员工表中的多对一相关 服务表与StaffMemberService表中的staffMember多对多相关 我有许多与staffMember表相关的任命详情表 您可以在此图中看到详细信息: 查询哪些服务有开放的时间段是非常昂贵的 --select * from ServiceProvider where Id > = 636 and CityId =
--select * from ServiceProvider where Id > = 636 and CityId = 4
DECLARE @longx NVARCHAR(20);
DECLARE @laty NVARCHAR(20);
DECLARE @userCityId INT;
DECLARE @userLocation GEOMETRY;
Declare @serviceName NVARCHAR(50);
declare @startDate AS DATE;
declare @endDate AS DATE;
SET @longx = '24.72977896594770';
SET @laty = '46.82470379239910';
SET @userCityId = 4;
SET @serviceName = '%hair%'
SET @userLocation = geometry::STPointFromText('POINT(' + @laty + ' ' + @longx + ')',0);
SET @startDate = '2019-06-01';
SET @endDate = '2019-06-05';
DECLARE @compareParts AS INT;
SET @compareParts = DATEDIFF(DAY, @startDate, @endDate) * 40 ;
-- get all services like serviceName
-- find out which SP offer them
-- find out if sp has availble time in the specific dates
WITH Serv AS
(
SELECT s.*
FROM Services s
INNER JOIN ServiceProvider sp ON sp.Id = s.ServiceProviderId
WHERE sp.CityId = @userCityId
AND s.Name LIKE @serviceName
),
StaffServices AS
(
SELECT s.*
FROM StaffMembers s
INNER JOIN StaffMemberService sms ON sms.StaffMemberId = s.Id
INNER JOIN Serv ON sms.ServiceId = Serv.Id
),
StaffMemberAppointment AS
(
SELECT ad.StaffMemberId, ad.Id, ad.Duration,a.ServiceProviderId
FROM AppointmentDetails ad
INNER JOIN Appointments a ON ad.AppointmentId = a.Id
INNER JOIN ServiceProvider sp ON sp.Id = a.ServiceProviderId
INNER JOIN StaffMemberService sms ON sms.StaffMemberId = ad.StaffMemberId
INNER JOIN Serv ON Serv.Id = sms.ServiceId
WHERE a.StartDt BETWEEN @startDate AND @endDate
),
appointmentParts AS
(
SELECT
sa.StaffMemberId, sa.ServiceProviderId,
SUM(Datepart(minute, sa.duration) + DATEPART(hour, sa.duration) * 60 ) /15 AS appointmentsparts
FROM
StaffMemberAppointment sa
GROUP BY
sa.StaffMemberId, sa.ServiceProviderId
)
SELECT
sm.*,
ap.appointmentsparts
FROM
StaffMembers sm
INNER JOIN
StaffServices ss ON ss.Id = sm.Id
LEFT JOIN
appointmentParts ap ON sm.Id = ap.StaffMemberId
我的基本想法是寻找服务的名称,比如提供的名称,然后我试图找到谁是可以提供服务的员工,并检查在特定日期范围内预订了多少预约时间,然后找到提供服务的服务提供商
IO统计a
(5 row(s) affected)
Table 'Appointments'. Scan count 0, logical reads 12, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'AppointmentDetails'. Scan count 5, logical reads 16, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'ServiceProvider'. Scan count 0, logical reads 20, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'StaffMemberService'. Scan count 3, logical reads 28, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Services'. Scan count 6, logical reads 18, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'StaffMembers'. Scan count 0, logical reads 10, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
时间间隔是15分钟。所以30分钟的预约是两个时段。
我找不到简化此查询的方法,有人能帮忙吗。如果您放弃CTE并使用带有外部应用程序的单一连接级别来计算约会时间段的数量,您会得到什么样的执行计划
SELECT sm.Id, sm.Name, sm.ServiceProviderId, sp.Name, appt.AppointmentSlots
FROM Services svc
INNER JOIN ServiceProvider sp ON sp.Id = svc.ServiceProviderId
INNER JOIN StaffMemberService sms ON sms.ServiceId = svc.Id
INNER JOIN StaffMembers sm ON sm.Id = sms.StaffMemberId
OUTER APPLY
(
SELECT SUM( Datepart(minute, ad.duration)
+ Datepart(hour, ad.duration)*60
) / 15 AS AppointmentSlots
FROM Appointments a INNER JOIN AppointmentDetails ad
ON ad.AppointmentId = a.Id
WHERE a.ServiceProviderId = sp.ID
AND ad.StaffMemberId = sms.StaffMemberId
AND a.StartDt between @startDate and @endDate
) appt
WHERE sp.CityId = @userCityId
AND svc.Name like @serviceName
AND ( AppointmentSlots < @maxSlots
OR AppointmentSlots IS NULL
)
你看过执行计划了吗?@DanielMann是的,它很大,我可以粘贴她你可以使用此网站通过计划@M.Kanarkowski谢谢:过滤谓词AppointSlots<@maxSlots或AppointSlots为null的计划正在被应用为查询的最后一步,使得整个查询比必要的更昂贵。我会将其移动到最内部的CTE,至少在任命部分内部。此外,除了PK之外,任命相关表上存在哪些索引?它没有给出正确的结果,我需要汇总每个员工的职位,以确定该员工是否有开放的任命。我已经创建了服务中的姓名索引,ServiceProvider中的CityId,约会表中的startdt和endDt。。。您是否100%确定原始查询正确计算总数?我可能错了,但是。。。似乎约会cte正在创建交叉连接-这当然可以解释查询速度慢/代价高的原因…在AppointDetails中,AppointDetails.ServiceId和Serv.Id之间没有连接,这将创建部分交叉连接并导致插槽数不正确。。。