因此,我在SQL Server 2008 R2中得到了一个查询(我用作存储过程)。 它有效,但我不相信没有更有效的方法。
数据位于表' ServiceInstance'中。这是一个完全平坦的表,包含 16 '实例'每个IPAddress,每个IPAddress都有一个唯一的TCPPort用于该IPAddress。
列' isRestarting'和' isInuse'对这个系统来说并不重要; 当“正在重新开始”时或者' isInUse'是 True ,' IsAvailable'是错误
列' CPUId'是;每个服务器有4个CPU - 运行的Delhpi应用程序同时只能在CPU上有1个应用程序。因此,当具有IP' 192.168.4.151'的服务器上的CPU#1时正在使用中,不允许从查询返回该IP上的CPUId。 (一台服务器上有16个实例,有4个核心)
)
因此,SP必须执行以下操作:
获取可用的实例,该实例必须符合:
因此。有了这些信息,我就创造了这个怪物:
UPDATE top(1) ServiceInstance
SET
LastRequestDate=GETDATE()
,IsInUse=1
,IsAvailable=0
OUTPUT
inserted.ServiceInstanceId,
inserted.IpAddress,
inserted.TcpPort,
inserted.LastRequestDate,
inserted.IsInUse
WHERE
ServiceInstanceId IN
(
SELECT Top (1) ServiceInstanceId FROM ServiceInstance
WHERE
(ServiceInstance.IsAvailable = 1 AND ServiceInstance.IsEnabled = 1)
AND ServiceInstanceId NOT IN
(
SELECT NGI1.ServiceInstanceId
FROM
(SELECT CpuId,IpAddress
FROM [ServiceInstance] NGI
WHERE IsInUse=1) a
INNER JOIN ServiceInstance AS NGI1 ON a.IpAddress = NGI1.IpAddress AND a.CpuId = NGI1.CpuId
)
ORDER BY LastRequestDate ASC
)
但是,我觉得这不是最有效的方法。 这个查询应该在窥视时间每秒运行~10次,因此目前在我的SQL Server上施加了一些沉重的CPU压力。
欢迎任何提示!我觉得我应该可以使用PARTITION OVER或加入我自己的桌子,但我似乎无法成功创建它......!
好的,表结构如下:
在这一刻,我没有索引。这是因为表变异了很多(每次使用ServerInstance时都会使用'表变异3或4次 (1 = 使用,2 = 使用后重启,3 =设置 IsAvailable ,4 = 失败时重启) 我的猜测是,如果我做了索引,那么每个突变都必须更新。不确定,但我觉得它会降低性能:)。
执行计划:
一些负载测试后的重要添加:
我真的需要使用Exec @RC =sp_getapplock @Resource='MyLock', @LockMode='Exclusive', @LockOwner='Transaction', @LockTimeout = 1000
这个StoredProcedure。没有它就行不通!
答案 0 :(得分:1)
WITH UnAvailableCpus AS (
SELECT IpAddress
,CpuId
FROM ServiceInstance
WHERE IsAvailable = 0
GROUP BY IpAddress
,CpuId
)
,AvailableInstances AS (
SELECT ServiceInstanceId
,LastRequestDate
FROM ServiceInstance
LEFT JOIN UnavailableCpus
ON UnavailableCpus.IpAddress = ServiceInstance.IpAddress
AND UnavailableCpus.CpuId = ServiceInstance.CpuId
WHERE ServiceInstance.IsAvailable = 1
AND ServiceInstance.IsEnabled = 1
AND UnavailableCpus.IpAddress IS NULL
)
,PreferredInstance AS (
SELECT TOP 1 ServiceInstanceId
FROM AvailableInstances
ORDER BY LastRequestDate
)
UPDATE ServiceInstance
SET
LastRequestDate=GETDATE()
,IsInUse=1
,IsAvailable=0
OUTPUT
inserted.ServiceInstanceId
,inserted.IpAddress
,inserted.TcpPort
,inserted.LastRequestDate
,inserted.IsInUse
WHERE ServiceInstanceId IN (SELECT ServiceInstanceId FROM PreferredInstance)
答案 1 :(得分:1)
它可能与表的结构有关(如果你发布它我们可以进一步阐述)。
最好的猜测是为任何用于连接的列创建索引(如果尚未完成):
为用于where条件的列创建索引也不错:
无论如何,你提出的这是一个"计划"用于诸如分布式操作系统之类的过程执行的算法。这种算法总是被编程为在内存中具有所有信息,并且执行规划(选择执行什么和在哪里)以编译为本机代码。例如,在Linux内核的情况下,在C ++中。如果将信息委托给数据库引擎,并规划为三级嵌套SQL,性能将会很糟糕。数据库更适合处理结果的大量信息,或者为许多客户同时查询信息,或者快速记录和存储大量数据。
也许您应该尝试使用面向对象的方法在Delphi中编写所有内容,而不使用数据库和SQL。
答案 2 :(得分:0)
尝试此查询以替换您的检索查询:
select top 1 tbl.serviceinstanceid from
(select
ipaddress,
cpuid,
sum(case when isavailable = 1 then 1 else 0 end)
over (partition by ipaddress, cpuid order by ipaddress, cpuid) s
from tbl
where isenabled = 1
) t
inner join serviceinstance tbl on tbl.ipaddress = t.ipaddress and tbl.cpuid = t.cpuid
where t.s = 4
and tbl.isinuse = 0
order by lastrequestdate
假设:具有1和0值的4个字段属于bit
类型。
故障: