SQL ROW_NUMBER() 过度性能问题

2024-03-16

我有这个 SQL 工作正常。

希望我的过滤器返回具有最高 UserSessionSequenceID 的最新唯一 SessionGuids。

问题是性能很糟糕 - 即使我有很好的索引。 我如何重写它 - 以省略 ROW_NUMBER 行?

SELECT TOP(@resultCount) * FROM 
(
    SELECT
        [UserSessionSequenceID]
        ,[SessionGuid]
        ,[IP]
        ,[Url]
        ,[UrlTitle]
        ,[SiteID]
        ,[BrowserWidth]
        ,[BrowserHeight]
        ,[Browser]
        ,[BrowserVersion]
        ,[Referer]
        ,[Timestamp]
        ,ROW_NUMBER() over (PARTITION BY [SessionGuid] 
                                    ORDER BY UserSessionSequenceID DESC) AS sort 
   FROM [tblSequence]
) AS t     
WHERE ([Timestamp] > DATEADD(mi, -@minutes, GETDATE())) 
  AND (SiteID = @siteID) 
  AND sort = 1
ORDER BY [UserSessionSequenceID] DESC

多谢 :-)


即使我有很好的索引

无意冒犯,但让我们来判断一下。始终发布exact当询问 SQL Server 性能问题时,表的架构,包括所有索引和基数。

例如,让我们考虑以下表结构:

create table tblSequence (
 [UserSessionSequenceID] int not null
        ,[SessionGuid] uniqueidentifier not null
        ,[SiteID] int not null
        ,[Timestamp] datetime not null
        , filler varchar(512));
go

create clustered index cdxSequence on tblSequence (SiteID, [Timestamp]);
go

与您的相同,但与性能问题无关的所有字段都聚合到通用填充符中。让我们看看,例如,大约 50k 会话的 1M 行的性能有多差?让我们用随机数据填充表格,但我们将模拟“用户活动”的内容:

set nocount on;
declare @i int = 0, @sc int = 1;
declare @SessionGuid uniqueidentifier = newid()
    , @siteID int = 1
    , @Timestamp datetime = dateadd(day, rand()*1000, '20070101')
    , @UserSessionSequenceID int = 0;
begin tran;
while @i<1000000
begin
    insert into tblSequence (
        [UserSessionSequenceID]
        ,[SessionGuid]
        ,[SiteID]
        ,[Timestamp]
        , filler)
    values (
        @UserSessionSequenceID
        , @SessionGuid
        , @siteID
        , @timestamp
        , replicate('X', rand()*512));

    if rand()*100 < 5
    begin
        set @SessionGuid = newid();
        set @siteID = rand() * 10;
        set @Timestamp = dateadd(day, rand()*1000, '20070101');
        set @UserSessionSequenceID = 0;
        set @sc += 1;
    end
    else
    begin
        set @timestamp = dateadd(second, rand()*300, @timestamp);
        set @UserSessionSequenceID += 1;
    end

    set @i += 1;
    if (@i % 1000) = 0
    begin
        raiserror(N'Inserted %i rows, %i sessions', 0, 1, @i, @sc);
        commit;
        begin tran;
    end
end
commit;

这大约需要 1 分钟才能充满。现在让我们查询您提出的相同查询:过去 Y 分钟内站点 X 上的任何用户会话的最后一个操作是什么?我必须使用@now的特定日期而不是GETDATE(),因为emy dtaa是模拟的,而不是真实的,所以我使用为SiteId 1随机填充的最大时间戳:

set statistics time on;
set statistics io on;

declare @resultCount int = 30;
declare @minutes int = 60*24;
declare @siteID int = 1;
declare @now datetime = '2009-09-26 02:08:27.000';

SELECT TOP(@resultCount) * FROM  
( 
    SELECT 
        [UserSessionSequenceID] 
        ,[SessionGuid] 
        , SiteID
        , Filler
        ,[Timestamp] 
        ,ROW_NUMBER() over (PARTITION BY [SessionGuid]  
                                    ORDER BY UserSessionSequenceID DESC) AS sort  
   FROM [tblSequence] 
   where SiteID = @siteID
   and [Timestamp] > DATEADD(mi, -@minutes, @now)
) AS t      
WHERE sort = 1 
ORDER BY [UserSessionSequenceID] DESC ;

这与您的查询相同,但限制性过滤器已移动insideROW_NUMBER() 部分子查询。结果返回:

Table 'tblSequence'. Scan count 1, logical reads 12, physical reads 0.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 31 ms.

热缓存上的响应时间为 31 毫秒,从表的近 60k 页中读取了 12 页。

Updated

再次阅读原始查询后,我意识到修改后的查询是不同的。你只需要new会议。我仍然相信通过 SiteID 和 Timestmap 进行过滤是获得必要性能的唯一方法,因此解决方案是使用 NOT EXISTS 条件验证候选发现:

SELECT TOP(@resultCount) * FROM  
( 
    SELECT 
        [UserSessionSequenceID] 
        ,[SessionGuid] 
        , SiteID
        , Filler
        ,[Timestamp] 
        ,ROW_NUMBER() over (
            PARTITION BY [SessionGuid]  
            ORDER BY UserSessionSequenceID DESC) 
         AS sort  
   FROM [tblSequence] 
   where SiteID = @siteID
   and [Timestamp] > DATEADD(mi, -@minutes, @now)
) AS new
WHERE sort = 1 
and not exists (
    select SessionGuid 
    from tblSequence
    where SiteID = @siteID
    and SessionGuid = new.SessionGuid
    and [TimeStamp] < DATEADD(mi, -@minutes, @now)
)
ORDER BY [UserSessionSequenceID] DESC 

这在我的笔记本电脑上返回,在 40 毫秒内从热缓存中返回超过 400k 会话的 1M 行:

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0
Table 'tblSequence'. Scan count 2, logical reads 709, physical reads 0

 SQL Server Execution Times:
   CPU time = 16 ms,  elapsed time = 40 ms.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SQL ROW_NUMBER() 过度性能问题 的相关文章

随机推荐

  • Android-NDK-添加本机支持-NDK 位置在首选项中无效

    我正在尝试使用调试模式 调试为 Android 本机应用程序 控制台说我需要添加本机支持 但是 当我按照说明进行操作时 它显示如下图 我应该如何处理 NDK 位置在首选项中无效 任何意见将是有益的 我对此很陌生 谢谢 该示例是 NDK 示例
  • 为带有附件的电子邮件设置多部分

    从我的应用程序中 我发送带有附件的邮件 完整的代码在这里 public int sendMail MailDraft mailDraftInstance mailInstance path Send the mail String mail
  • 为什么.NET Core DI容器不注入ILogger?

    我正在尝试在基于 NET Core 2 1 的 C 控制台应用程序中登录并运行 我将以下代码添加到我的 DI 声明中 var sc new ServiceCollection sc AddLogging builder gt builder
  • GDB 在 macOS Catalina 上冻结

    我在 mac 上运行了 helloworld 来尝试 GDB 但在输入 run 后输出 New Thread 0x1903 of process 69034 然后就什么也没有了 我等了一个小时了 还是没有任何动静 完成认证并禁用startu
  • 使用 PDO 连接 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 刚刚开始使用 PDO 请解释我的连接
  • 如何使用 PHP 打印 JavaScript

    我需要将一些 JS 变量传递给 PHP 但遇到了一些麻烦 我已经尝试过以下方法 product id echo product id 但这只是将其打印为字符串 我将如何存储该 JS 变量然后echo它使用 PHP 吗 我对 PHP 很陌生
  • 不同数据的单独链接/关联表?

    哪种设计方法更好 为数据库中的每种数据类型建立单独的链接 关联表 还是将通用标识合并到公共链接 关联表中 因为如果没有例子这个问题真的没有意义 假设我有一个数据库 其中包含作者和书籍的数据 使用人们可以轻松掌握和识别的示例 为了简单起见 每
  • 如何用 C 语言检查 Windows 上的目录是否存在?

    Question 在 Windows C 应用程序中 我想验证传递给函数的参数以确保指定的路径存在 如何用 C 语言检查 Windows 上的目录是否存在 我知道你可能会陷入竞争条件 在你检查路径是否存在和使用它不再存在的时间之间 但我可以
  • 如何调整组合框下拉列表中的字符?

    如何证明下拉部分中列出的值的合理性ttk Combobox 我努力了justify center 但这似乎只配置所选项目 如果有的话也可以使用资源链接 我找不到它 try In order to be able to import tkin
  • MediaSource 从不在 React 中发出 sourceopen 事件

    我正在尝试在 React 自定义挂钩中使用 Javascript 的 MediaSource API 流式传输视频文件 这是我的代码片段 const useMyHook videoRef React MutableRefObject
  • 如何使用 Google Closure 编译器删除未使用的 JavaScript 代码?

    如何使用 Google Closure 编译器删除未使用的代码 我正在使用 JQuery Slider 控件 但没有使用 JQuery 中的其他任何内容 所以我读到了 Google Closure 编译器Advanced模式可以删除未使用的
  • 为什么 Whitenoise 在 Heroku 上的默认 Django 项目中崩溃?

    我正在尝试按照 Heroku 的说明启动一个新的 Django 应用程序 当我开始激活白噪音时 它崩溃了 我什至还没有编写任何应用程序代码 出了什么问题 这是网络工作者崩溃的回溯 2015 06 26 20 37 36 0000 11 ER
  • 关系中的核心数据总和

    我有一个类别实体 有很多费用 我想获得给定月份内某个类别的所有费用总和 NSNumber totalForMonth NSDate date NSPredicate sumPredicate NSPredicate predicateWit
  • 为什么php的mail()函数发送邮件成功但字段为空?

    电子邮件已到达目标地址 但字段为空 原因是什么 我的使用mail 如下
  • 使用 keras 保存的 ML.NET 加载模型

    我有一个用 Python 和 Keras 实现的神经网络 训练完成后 我导出了模型 并得到了两个文件 model js 和 model h5 现在我想在 NET 项目中进行实时分类 并且我想使用经过训练的神经网络 ML NET 中是否有一种
  • 在 R 绘图子图上获取单独的轴标签

    使用 R 时plotly包版本 4 5 6 我无法弄清楚如何在使用组合多个图时显示轴标签subplot 以下是未显示 x 轴标签的示例 require plotly a lt data frame x1 1 3 y 30 32 b lt d
  • 获取 MongoDB 中数组的第 n 个元素

    作为 MongoDB 文档的一部分 我存储了一个对象数组 例如 如何仅查询数组的第四个元素 所以我不想取出整个数组 只取出第四个元素 Use slice db foo find bar xyz my array slice n 1 将检索
  • 没有名为flask_script的模块

    我正在尝试运行一个需要flask script 的程序 Flask既安装在我的机器上 又安装在虚拟环境中 我无法让我的机器或虚拟环境找到flask script 请指教 运行Ubuntu 你真的安装了 Flask Script 吗 如果没有
  • 从mongodb集合中获取最新记录

    我想知道集合中最新的记录 怎么做 注意 我知道以下命令行查询有效 1 db test find sort idate 1 limit 1 forEach printjson 2 db test find skip db test count
  • SQL ROW_NUMBER() 过度性能问题

    我有这个 SQL 工作正常 希望我的过滤器返回具有最高 UserSessionSequenceID 的最新唯一 SessionGuids 问题是性能很糟糕 即使我有很好的索引 我如何重写它 以省略 ROW NUMBER 行 SELECT T