SQL查询提高了所需的性能(1表)

时间:2014-06-19 08:10:18

标签: sql sql-server

因此,我在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个核心)

The table with data

因此,SP必须执行以下操作:

获取可用的实例,该实例必须符合:

  • SP应始终返回1行。
    • 对于我来说这是一个低价格 - 如果需要我可以重新运行SP
  • ServerInstance' IsEnabled必须是真的
  • 返回ServerInstance时,必须将其设置为' IsAvailable' = False所以它不会再被选中,直到工作完成(由我的应用程序逻辑完成重置)
  • 该IP上的所有CPUId都不一定是' IsAvailable = False'
    • 这可确保该服务器上的CPU#是免费的
  • 没有使用最长的ServerInstance是首选。
    • 因为我有一个大型游泳池,想要加载平衡流量
  • 发现' ServerInstance将立即更新。
    • ' LastRequestDate'应加盖印章
    • ' IsInuse'设置为True
    • ' IsAvailable'设为错误

因此。有了这些信息,我就创造了这个怪物:

 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或加入我自己的桌子,但我似乎无法成功创建它......!

好的,表结构如下:

  • ServiceInstanceId INT NOT NULL
  • IPAddres varchar(20)NOT NULL
  • TCPPort varchar(5)NOT NULL
  • LastRequestDate DateTime NOT NULL
  • IsEnabled BIT NOT NULL
  • IsAvailable BIT NOT NULL
  • IsRestarting BIT NOT NULL
  • IsInuse BIT NOT NULL
  • CPU INT NOT NULL

在这一刻,我没有索引。这是因为表变异了很多(每次使用ServerInstance时都会使用'表变异3或4次 (1 = 使用,2 = 使用后重启,3 =设置 IsAvailable ,4 = 失败时重启) 我的猜测是,如果我做了索引,那么每个突变都必须更新。不确定,但我觉得它会降低性能:)。

执行计划: Execution plan for my query:

一些负载测试后的重要添加:

我真的需要使用Exec @RC =sp_getapplock @Resource='MyLock', @LockMode='Exclusive', @LockOwner='Transaction', @LockTimeout = 1000这个StoredProcedure。没有它就行不通!

3 个答案:

答案 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)

它可能与表的结构有关(如果你发布它我们可以进一步阐述)。

最好的猜测是为任何用于连接的列创建索引(如果尚未完成):

  • CPUID
  • Ip地址
  • IsInUse

为用于where条件的列创建索引也不错:

  • IsAvailable
  • IsEnabled

无论如何,你提出的这是一个"计划"用于诸如分布式操作系统之类的过程执行的算法。这种算法总是被编程为在内存中具有所有信息,并且执行规划(选择执行什么和在哪里)以编译为本机代码。例如,在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类型。

故障:

  • Sum用于检查每个IP地址中有多少4个CPUID可用。我们只对sum = 4的那些感兴趣。
  • 必须启用所有内容。
  • 选择时不得使用。
  • 必须是上次请求日期的最小值。