我有以下架构的表:
现在,我正在尝试编写一个提供设备的查询,以及该设备具有的不同软件和服务的数量。
如果我运行以下查询,我会在5秒内得到一个结果(设备有50,000行,软件和服务都有200个,链接表包含每个软件和服务的每个设备的链接。仅用于测试目的)
SELECT
device.name
,COUNT(DISTINCT(device_software.softwareId))
FROM
device
LEFT OUTER JOIN
device_software ON device.deviceId = device_software.deviceId
GROUP BY device.name
但如果我尝试扩展查询以包含两者的计数,则需要更长的时间(约30分钟仍在继续):
SELECT
device.name
,COUNT(DISTINCT(device_software.softwareId))
,COUNT(DISTINCT(device_service.serviceId))
FROM
device
LEFT OUTER JOIN
device_service ON device.deviceId = device_service.deviceId
LEFT OUTER JOIN
device_software ON device.dDeviceId = device_software.deviceId
GROUP BY device.name
既然这是在存储过程中,我可以单独获得两个计数并将其组合,但这似乎是一个黑客。我想知道是否有人知道在没有大量性能影响的情况下在单个查询中执行此操作的更好方法?
答案 0 :(得分:2)
我会尝试以下内容,看看它是否有所不同:
SELECT
device.name
a.cntSft, b.cntSrv
FROM device
LEFT JOIN
( SELECT deviceId, COUNT(DISTINCT softwareId) as cntSft FROM device_software
GROUP BY deviceId) a (ON a.deviceId = device.deviceId)
LEFT JOIN
( SELECT deviceId, COUNT(DISTINCT serviceId) as cntSrv FROM device_service
GROUP BY deviceId) b (ON b.deviceId = device.deviceId);
您可能也不需要COUNT DISTINCT
,只需COUNT
这个版本的查询。
答案 1 :(得分:0)
您可以考虑Device_Software和Device_Service上的索引视图:
CREATE VIEW dbo.v_Device_Software
WITH SCHEMABINDING
AS
SELECT DeviceId, SoftwareId, DeviceCount = COUNT_BIG(*)
FROM dbo.Device_Software
GROUP BY DeviceId, SoftwareId;
GO
CREATE UNIQUE CLUSTERED INDEX x ON dbo.v_Device_Software(DeviceId, SoftwareId);
GO
CREATE VIEW dbo.v_Device_Service
WITH SCHEMABINDING
AS
SELECT DeviceId, ServiceId, DeviceCount = COUNT_BIG(*)
FROM dbo.Device_Service
GROUP BY DeviceId, ServiceId;
GO
CREATE UNIQUE CLUSTERED INDEX x ON dbo.v_Device_Service(DeviceId, ServiceId);
GO
现在您的查询变为:
SELECT
device.name
,COUNT(vsoft.DeviceId)
,COUNT(vserv.DeviceId)
FROM
dbo.device
LEFT OUTER JOIN dbo.v_Device_Service AS vserv
ON device.deviceId = vserv.DeviceId
LEFT OUTER JOIN dbo.v_Device_Software AS vsoft
ON device.deviceId = voft.DeviceId
GROUP BY device.name;
但是,有许多限制,您应该确保测试它对整个工作负载的影响,而不仅仅是这一个查询。