SQL Server 2005 游标跑的很慢!

本文通过对比分析在SQL Server Management Studio中使用游标的性能表现,发现将游标封装到存储过程中可以显著提升运行效率。文章详细记录了游标在不同场景下的运行时间,并探讨了事务设置对性能的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 本人使用SQL Server Management Studio 在查询界面中写了两个游标, 份别跑了30分钟和6分钟.

 这两个游标都是只读前进地提取.涉及数量9万和5千条,也就是说提取次数.

 无论对要提取的表增加索引,还是修改Cursor的类型,都无济于事!  微软不会那么差劲吧?

 

 后来感觉放进存储器起跑,确实很快.整个跑下来才1分钟48秒.!

 

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE <Procedure_Name, sysname, ProcedureName>
 -- Add the parameters for the stored procedure here
 <@Param1, sysname, @p1> <Datatype_For_Param1, , int> = <Default_Value_For_Param1, , 0>,
 <@Param2, sysname, @p2> <Datatype_For_Param2, , int> = <Default_Value_For_Param2, , 0>
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from


默认情况下没有一下事务设置的

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

 

    -- Insert statements for procedure here
 SELECT <@Param1, sysname, @p1>, <@Param2, sysname, @p2>
END
GO

 

 今天单独拿出一部分游标来测试。分别放在两个查询框中。有个有事务设置,另外个没有

结果有的跑了34秒,没有的跑了6分11秒 

<think>嗯,用户的问题是关于SQL Server存储过程导致客户端执行变慢的原因和解决方法。我需要先理解存储过程在什么情况下会导致客户端变慢。存储过程本身通常被认为是优化性能的手段,但有时候执行起来反而慢,可能有哪些原因呢? 首先,存储过程本身的执行效率可能有问题。比如,里面的查询没有优化,缺少索引,或者有复杂的计算。另外,存储过程可能生成了大量中间结果,比如临时表或者游标,这些都会占用资源。还有可能是参数嗅探的问题,当存储过程第一次编译时使用的参数不适合后续的执行计划,导致性能下降。 然后,网络传输也是一个因素。如果存储过程返回的结果集太大,客户端需要等待数据传输完成,这会让用户感觉慢。比如,如果存储过程返回了百万行数据,网络带宽不足或者延迟高的话,传输时间就会很长。 客户端处理逻辑的问题也可能导致变慢。比如,客户端可能在获取数据后进行了复杂的处理,或者在循环中频繁调用存储过程,增加了整体时间。此外,应用程序设计不合理,比如没有使用分页而一次性加载大量数据,也会让客户端卡顿。 资源竞争方面,服务器上的CPU、内存、磁盘IO如果不足,存储过程执行时会变慢。比如,内存不足导致频繁的磁盘交换,或者磁盘IO瓶颈让查询变慢。同时,阻塞和死锁也会让存储过程执行时间延长,客户端自然觉得慢。 解决方案的话,应该从存储过程优化开始。检查里面的SQL语句,确保有合适的索引,避免全表扫描。减少临时表和游标的使用,改用更高效的集合操作。处理参数嗅探问题,可以使用局部变量或者OPTIMIZE FOR提示。另外,控制返回的数据量,比如添加分页参数,只返回必要的数据。 网络传输优化方面,可以压缩结果集,或者使用异步查询,让客户端在后台获取数据。客户端处理逻辑需要优化,比如减少不必要的循环调用,使用缓存避免重复执行相同存储过程。分批处理大数据,而不是一次性处理。 资源调优方面,调整SQL Server的内存配置,比如设置最大内存限制,避免资源争抢。优化磁盘配置,使用SSD或者分离数据文件和日志文件。监控和解决阻塞、死锁问题,使用适当的隔离级别和索引减少锁竞争。 另外,定期维护数据库,比如重建索引、更新统计信息,确保执行计划正确。检查存储过程的编译和重编译情况,避免频繁重编译带来的开销。使用性能监控工具,如SQL Server Profiler,找出慢的查询并进行优化。 可能还需要考虑数据库设计和架构调整,比如分区表处理大数据,读写分离分散压力,引入缓存层减少数据库访问次数。如果存储过程中的业务逻辑过于复杂,可以拆分到应用层,或者使用CLR集成来优化计算密集型操作。 用户提供的引用中也提到了一些点,比如使用存储过程减少网络开销,避免返回大的结果集,配置虚拟内存和服务器内存参数,重建索引和收缩数据库等。这些都需要综合起来分析,找到导致性能瓶颈的具体原因,然后针对性地解决。</think>### SQL Server存储过程执行缓慢的原因分析及解决方案 #### 一、根本原因分析 1. **存储过程执行效率问题** - 存在未优化的查询语句(如全表扫描、缺失索引) - 复杂计算或临时表过度使用(如使用游标循环处理数据) - 参数嗅探(Parameter Sniffing)导致执行计划不匹配[^1][^4] 2. **网络传输瓶颈** - 返回结果集过大(如未分页的百万级数据) - 客户端与服务器间高延迟或带宽不足[^1][^3] 3. **客户端处理逻辑缺陷** - 数据后处理耗时(如内存中复杂计算) - 频繁调用存储过程(如循环内嵌套调用)[^3] 4. **资源竞争与配置问题** - 服务器内存/CPU资源不足(如未合理配置`max server memory`) - 磁盘I/O瓶颈(如日志文件与数据文件共用物理磁盘)[^2] #### 二、针对性解决方案 ##### (一) 存储过程优化 1. **查询优化** - 添加缺失索引(通过`EXEC sp_helpindex`分析) - 使用`SET STATISTICS IO ON`检查逻辑读次数 - 示例:将游标改为集合操作 ```sql -- 原始游标方式 DECLARE @id INT DECLARE cur CURSOR FOR SELECT id FROM table OPEN cur FETCH NEXT FROM cur INTO @id WHILE @@FETCH_STATUS = 0 BEGIN -- 单行处理逻辑 FETCH NEXT FROM cur INTO @id END CLOSE cur DEALLOCATE cur -- 优化为集合操作 UPDATE table SET column = calculation FROM table ``` 2. **参数嗅探处理** ```sql CREATE PROCEDURE usp_GetData @Param1 INT WITH RECOMPILE -- 强制重新编译 AS BEGIN SELECT * FROM table WHERE column = @Param1 END ``` 或使用局部变量隔离参数: ```sql CREATE PROCEDURE usp_GetData @Param1 INT AS BEGIN DECLARE @LocalParam INT = @Param1 SELECT * FROM table WHERE column = @LocalParam END ``` 3. **结果集控制** ```sql CREATE PROCEDURE usp_GetPagedData @PageSize INT = 50, @PageNumber INT = 1 AS BEGIN SELECT * FROM table ORDER BY id OFFSET (@PageNumber - 1) * @PageSize ROWS FETCH NEXT @PageSize ROWS ONLY END ``` ##### (二) 网络传输优化 1. **数据压缩** ```sql -- 启用压缩(SQL Server 2008+) CREATE PROCEDURE usp_GetCompressedData AS BEGIN SELECT * FROM table OPTION (COMPRESS_ROW) END ``` 2. **异步查询模式** (C#示例) ```csharp using (SqlCommand cmd = new SqlCommand("usp_LongProcess", connection)) { cmd.CommandType = CommandType.StoredProcedure; connection.Open(); IAsyncResult result = cmd.BeginExecuteNonQuery(); // 执行其他操作 cmd.EndExecuteNonQuery(result); } ``` ##### (三) 客户端优化 1. **批量处理优化** ```csharp // 错误方式:逐条提交 foreach(var item in list) { ExecuteProc("usp_ProcessItem", item.ID); } // 正确方式:批量提交 DataTable dt = BuildBulkDataTable(list); ExecuteProc("usp_ProcessBatch", dt); ``` 2. **缓存策略** ```sql CREATE PROCEDURE usp_GetCachedData AS BEGIN IF OBJECT_ID('tempdb..##CachedData') IS NOT NULL SELECT * FROM ##CachedData ELSE BEGIN SELECT * INTO ##CachedData FROM source_table SELECT * FROM ##CachedData END END ``` ##### (四) 服务器资源调优 1. **内存配置公式** $$ \text{max server memory} = \text{Physical Memory} \times 0.75 $$ 通过以下命令设置: ```sql EXEC sys.sp_configure N'max server memory (MB)', 12288 RECONFIGURE ``` 2. **磁盘优化组合** | 文件类型 | 推荐磁盘类型 | RAID级别 | |----------------|--------------|----------| | 数据文件 | SSD | RAID 10 | | 事务日志 | SAS 15k RPM | RAID 1 | | TempDB | NVMe | RAID 0 | #### 三、深度优化工具链 1. **执行计划分析** ```sql SET SHOWPLAN_XML ON EXEC usp_ProblemProcedure SET SHOWPLAN_XML OFF ``` 2. **扩展事件监控** ```sql CREATE EVENT SESSION [SP_Monitor] ON SERVER ADD EVENT sqlserver.rpc_completed( WHERE ([sqlserver].[like_i_sql_unicode_string]([sqlserver].[database_name],N'YourDB')) ) ADD TARGET package0.event_file(SET filename=N'SP_Monitor.xel') ``` #### 四、典型场景案例 **场景描述**: 某订单系统存储过程`usp_GetOrderReports`执行时间从2秒骤增至30秒。 **分析过程**: 1. 通过`sys.dm_exec_procedure_stats`发现平均逻辑读从5,000升至150,000 2. 检查执行计划发现索引`IX_Orders_Date`丢失 3. 参数嗅检测试显示传入`@StartDate='2020-01-01'`时使用全表扫描 **解决方案**: ```sql -- 重建索引 ALTER INDEX IX_Orders_Date ON Orders REBUILD -- 添加覆盖索引 CREATE NONCLUSTERED INDEX IX_Orders_Covering ON Orders (OrderDate) INCLUDE (CustomerID, TotalAmount, Status) -- 修改存储过程 ALTER PROCEDURE usp_GetOrderReports @StartDate DATETIME, @EndDate DATETIME AS BEGIN DECLARE @LocalStart DATETIME = @StartDate, @LocalEnd DATETIME = @EndDate SELECT OrderID, CustomerID, TotalAmount FROM Orders WITH (INDEX(IX_Orders_Covering)) WHERE OrderDate BETWEEN @LocalStart AND @LocalEnd OPTION (OPTIMIZE FOR (@LocalStart UNKNOWN, @LocalEnd UNKNOWN)) END ``` #### 五、进阶优化方向 1. **内存优化表** ```sql -- 创建内存优化文件组 ALTER DATABASE YourDB ADD FILEGROUP memopt_mod CONTAINS MEMORY_OPTIMIZED_DATA -- 创建内存优化表 CREATE TABLE dbo.SessionData ( SessionID INT NOT NULL PRIMARY KEY NONCLUSTERED, Data VARBINARY(MAX) ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY) ``` 2. **原生编译存储过程** ```sql CREATE PROCEDURE usp_NativeProc WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER AS BEGIN ATOMIC WITH ( TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english' ) -- 高性能处理逻辑 END ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值