我们正在使用 ODBC 连接到 SQL Server 2008 R2 实例,当在连接上启用 MARS 时,SELECT 查询的性能明显变慢。我尝试了不同的驱动程序版本(SQL Server Native Client 10.0、SQL Server Native Client 11.0),但 MARS 连接总是慢得多。我希望 MARS 连接中查询所花费的时间与 MARS 关闭所花费的时间相当,因为我一次只运行一个查询而没有任何交错。
关于 SELECT 查询: 我还没有研究其他查询,但是这个具有多个连接的查询在 MARS 开启时速度较慢。该查询返回 600K+ 行。我在下面进一步粘贴了查询。
简单的工作流程: a) 使用 ODBC 连接到 SQL Server 2008 R2 实例 b) SQLPrepare 查询 c) SQLExecute d) SQLFetch 多次,直到它返回 SQL_NO_DATA
当 MARS 关闭时: SQLExecute 大约需要 7 秒当 SQL_ATTR_ROW_ARRAY_SIZE 设置为 100 时,SQLFetch 被调用 6000+ 次,总提取时间(跨越 6000+ SQLFetch 调用)低于 300 毫秒 我的应用程序通常会获得完整的结果集(600K+ 行) ) 在 7.5 秒内(即从发出查询到接收最后一行)。
MARS 为 ON 时: SQLExecute 大约需要 7 秒当 SQL_ATTR_ROW_ARRAY_SIZE 设置为 100 时,SQLFetch 被调用 6000+ 次,总提取时间为 30+ 秒。我尝试了不同的行大小,但总提取时间通常为 30+ 秒,因为当行大小设置为更高的数字时,每个 SQLFetch 调用所花费的时间会增加。我的应用程序通常在大约 40 秒内(即从发出查询到接收最后一行)获得完整的结果集(600K+ 行)。
我尝试了不同的游标类型(包括 SQL Server 特定的 FAST FORWARD-ONLY 游标,带和不带自动提取)、SQL_ATTR_CONCURRENCY、SQL_ATTR_CURSOR_SCROLLABLE 和 SQL_ATTR_CURSOR_SENSITIVITY。我也尝试了不同的行获取大小。但是我无法在启用 MARS 的情况下提高查询的性能。
我觉得 MARS 正在使用游标,而当 MARS 关闭时正在使用默认结果集(“firehose cursors”);尽管在 Microsoft 文档中声称默认结果是启用 MARS 时的默认结果。
我正在使用的查询如下。我没有指定查询中使用的每一列的数据类型,但我现在将跳过它。如果这些信息对于解决这个问题是必要的,我绝对可以提供。
也许我的查询有一些特征导致 MARS 不使用默认结果集?我可以尝试在 MARS 下加快查询速度吗?我们需要在我们的应用程序上启用 MARS。
SELECT [G].[iteration] AS [iter],
[A].[area] AS [area],
[B].[status] AS [status],
DATEADD(minute, DATEDIFF(minute, 0, [B].[dt]), 0) AS [mydate],
MAX([Z].[title]) AS [title1],
MIN([Z].[title]) AS [title2],
MAX((CASE
WHEN 0 = ISNUMERIC(CAST([G].[estimate] AS VARCHAR)) THEN NULL
ELSE CAST(CAST([G].[estimate] AS VARCHAR) as float) END)) AS [calculation]
FROM [dbo].[Z] [Z]
INNER JOIN [dbo].[A] [A] ON ([Z].[idA] = [A].[idA])
INNER JOIN [dbo].[B] [B] ON ([Z].[idB] = [B].[idB])
INNER JOIN [dbo].[C] [C] ON ([Z].[idC] = [C].[idC])
INNER JOIN [dbo].[D] [D] ON ([Z].[idFF] = [D].[idFF])
INNER JOIN [dbo].[E] [E] ON ([Z].[idP] = [E].[idP])
LEFT JOIN [dbo].[F] [F] ON ([Z].[idB] = [F].[idB])
LEFT JOIN [dbo].[G] [G] ON ([Z].[idB] = [G].[idB])
LEFT JOIN [dbo].[H] [H] ON ([B].[idQ] = [H].[idQ])
INNER JOIN [dbo].[J] [J] ON ([Z].[idB] = [J].[idJ])
WHERE (([A].[area] >= 'AA') AND ([A].[area] <= 'ZZ'))
GROUP BY [G].[iteration],
[A].[area],
[B].[status],
DATEADD(minute, DATEDIFF(minute, 0, [B].[dt]), 0)