1

我有具有以下架构的表:

设备

  • 设备编号
  • 姓名

服务

  • 服务标识
  • 姓名

软件

  • 软件编号
  • 姓名

设备_软件

  • 设备编号
  • 软件编号
  • 发现日期

设备_服务

  • 设备编号
  • 服务标识
  • 发现日期

现在,我正在尝试编写一个查询,给出一个设备,以及该设备拥有的不同软件和服务的数量。

如果我运行以下查询,我会在 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

现在,由于这是在存储过程中,我可以单独获取两个计数并将其组合起来,但这似乎是一个 hack。我想知道是否有人知道在单个查询中执行此操作而不会对性能造成巨大影响的更好方法?

4

2 回答 2

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使用此版本的查询。

于 2012-08-29T17:00:52.380 回答
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;

但是,有很多限制,您应该确保测试这对您的整个工作负载的影响,而不仅仅是这个查询。

于 2012-08-29T16:50:13.037 回答