Sql server 为什么打开第二个ADO客户端记录集的速度如此之慢?

Sql server 为什么打开第二个ADO客户端记录集的速度如此之慢?,sql-server,vba,ms-access,ado,Sql Server,Vba,Ms Access,Ado,Repro 创建包含大量行的SQL Server表: CREATE TABLE largetable (field int); INSERT INTO largetable (field) SELECT TOP 10000 ROW_NUMBER() OVER(ORDER BY t1.number) FROM master..spt_values t1 CROSS JOIN master..spt_values; 创建新的VBA项目(例如Access或Excel 2016),并添加对“

Repro

  • 创建包含大量行的SQL Server表:

    CREATE TABLE largetable (field int);
    
    INSERT INTO largetable (field)
    SELECT TOP 10000 ROW_NUMBER() OVER(ORDER BY t1.number) 
      FROM master..spt_values t1 CROSS JOIN master..spt_values;
    
  • 创建新的VBA项目(例如Access或Excel 2016),并添加对“Microsoft ActiveX Data Objects 2.8(或6.1)库”的引用

  • 修改以下复制代码以将正确的连接字符串包含到SQL Server数据库。然后在VBA模块中执行它:

    Public Sub Repro()
    Dim cn作为新的ADODB.连接
    将r1调整为新ADODB.Recordset
    cn.ConnectionString=“驱动程序={SQL Server本机客户端11.0};服务器=…;数据库=…;受信任的_连接=是”
    中国公开赛
    可读cn'Fast(0.01-0.03s)
    r1.CursorLocation=adUseClient
    r1.打开“选择1”,cn,adOpenStatic
    可读cn'慢速(6-10秒)
    r1.关闭
    可读cn'慢速(6-10秒)
    设置r1=无
    可读cn'Fast(0.01-0.03s)
    cn.Close
    端接头
    私有子可读(ByVal cn作为ADODB.Connection)
    d为双色
    将r2调整为新的ADODB.Recordset
    d=计时器
    r2.CursorLocation=adUseClient
    r2.打开“从大表中选择字段”,cn,adOpenStatic
    打印计时器-d
    r2,结束
    设置r2=无
    端接头
    

  • 问题

    如您所见,如果另一个客户端游标已经打开,则打开另一个客户端游标的速度会非常慢。我想知道为什么会发生这种情况,以及我能做些什么


    更多详细信息

    使用SQL Server Profiler,我可以看到“慢”和“快”场景有所不同

    这就是“快速”查询的外观:

    SQL:BatchStarting   SELECT field FROM largetable
    SQL:StmtStarting    SELECT field FROM largetable
    SQL:StmtCompleted   SELECT field FROM largetable
    SQL:BatchCompleted  SELECT field FROM largetable
    
    RPC:Starting
      declare @p1 int
      set @p1=0
      declare @p3 int
      set @p3=16388
      declare @p4 int
      set @p4=8193
      declare @p5 int
      set @p5=0
      exec sp_cursoropen @p1 output,N'SELECT field FROM largetable',@p3 output,@p4 output,@p5 output
      select @p1, @p3, @p4, @p5
    
    RPC:Completed
      ...same SQL as above...
    
    RPC:Starting    exec sp_cursorfetch 180150003,2,0,1
    RPC:Completed   exec sp_cursorfetch 180150003,2,0,1
    RPC:Starting    exec sp_cursorfetch 180150003,2,0,1
    RPC:Completed   exec sp_cursorfetch 180150003,2,0,1
    RPC:Starting    exec sp_cursorfetch 180150003,2,0,1
    RPC:Completed   exec sp_cursorfetch 180150003,2,0,1
    ...repeat 10000 times...
    
    这就是“慢”查询的外观:

    SQL:BatchStarting   SELECT field FROM largetable
    SQL:StmtStarting    SELECT field FROM largetable
    SQL:StmtCompleted   SELECT field FROM largetable
    SQL:BatchCompleted  SELECT field FROM largetable
    
    RPC:Starting
      declare @p1 int
      set @p1=0
      declare @p3 int
      set @p3=16388
      declare @p4 int
      set @p4=8193
      declare @p5 int
      set @p5=0
      exec sp_cursoropen @p1 output,N'SELECT field FROM largetable',@p3 output,@p4 output,@p5 output
      select @p1, @p3, @p4, @p5
    
    RPC:Completed
      ...same SQL as above...
    
    RPC:Starting    exec sp_cursorfetch 180150003,2,0,1
    RPC:Completed   exec sp_cursorfetch 180150003,2,0,1
    RPC:Starting    exec sp_cursorfetch 180150003,2,0,1
    RPC:Completed   exec sp_cursorfetch 180150003,2,0,1
    RPC:Starting    exec sp_cursorfetch 180150003,2,0,1
    RPC:Completed   exec sp_cursorfetch 180150003,2,0,1
    ...repeat 10000 times...
    
    因此,当查询速度快时,所有数据都在一个批次中加载,而当查询速度慢时,每个记录都单独传输

    显然,我想强制ADO始终使用“快速”路由,即使另一个客户端游标已经打开


    附加注释

    • 我知道,
      Recordset.Open
      可以返回与请求的游标不同的游标类型。在这种情况下,在
      rs2.Open
      之后检查
      CursorType
      CursorLocation
      ,会发现在这两种情况下(慢和快)都会返回客户端静态光标

    • 我已经测试了以下SQL Server ODBC驱动程序,所有这些驱动程序都可以重现此问题:

      • “经典”MDAC
        {SQL Server}
        ODBC驱动程序
      • SQL Server本机客户端11.0
      • 最新的
    • SQL Server OLE DB驱动程序可能会重现此问题。我们使用ODBC而不是OLEDB,因为。我知道它在不久前还没有被弃用,但我们目前不打算迁移我们的DAL

    • 启用MARS(
      MARS\u Connection=yes
      )没有任何区别。SQL Server探查器显示两个记录集使用相同的连接。这是

    • 我们使用ADO而不是ADO.NET,因为MS Access尚未内置对.NET代码的支持

    • 我们不想使用服务器端游标。他们。我们刚从他们那里迁移出去


    如果在打开第二个记录集之前关闭第一个记录集,是否仍然很慢?@WhatstThePoint:closed:是的,仍然很慢。关闭并设置为“无”:不,快速。(请参阅复制代码中的
    fast/slow
    注释。)本机客户端也是,当前驱动程序是。它不太可能表现出不同的行为,但也许值得一试。谢谢,我明天会试试。(虽然我的直觉告诉我这是ODBC的OLE DB提供程序(MSDASQL)的问题,而不是ODBC驱动程序的问题。)@Andre:我试过了,同样的问题。