SQL Server存储了proc性能

时间:2011-02-15 20:23:04

标签: sql-server performance tsql

我有一个ASP.NET应用程序,它在存储过程中包含以下SQL查询:

SELECT @result = COUNT(id)
FROM course_tracking
WHERE employee_number = @employee_number
AND course_code = @course_code

IF @result = 0
BEGIN
    INSERT INTO COURSE TRACKING
END
ELSE
    UPDATE COURSE TRACKING

Course Tracking表中有几乎一百万行,每次执行此proc时,SQL事件探测器都显示介于40k和50k之间的读数,这只有几秒钟。

因为我不是一个SQL Server性能的人......纠正这个问题的最佳方法是什么?

非常感谢任何帮助。

由于

4 个答案:

答案 0 :(得分:4)

试试这个

IF EXISTS(SELECT 1 FROM course_tracking
WHERE employee_number = @employee_number
AND course_code = @course_code)
BEGIN
     UPDATE COURSE TRACKING
END
ELSE
BEGIN
     INSERT INTO COURSE TRACKING
END

答案 1 :(得分:1)

亚历,

大量阅读可能有很多原因,我相信@ Jonathan的回答会有所帮助,或者暂时掩盖这个问题。获取大量读取的原因是因为您缺少某些关键索引,和/或您的表统计信息不是最新的,或者它已关闭。

如果许多其他过程,视图和查询使用它,那么对像这样的大型表进行perf调整可能会很复杂。因为更改任何索引会对现在正常运行的其他查询产生巨大影响,但如果您的表缺少任何索引,那么任何更改都可能会有所帮助。当您尝试优化这样的事情时要考虑的事项是:

  1. 此查询的运行频率
  2. 当它运行时它会影响系统上的其他进程
  3. 最常见的操作是什么 在此表上,插入还是更新?
  4. 如果这个查询每天运行一次,或者很少,并且不会影响其他进程,我可能会倾向于离开它。但是,如果这是一个非常频繁地运行和/或影响其他进程的进程,那么您需要修复它。现在通过修复它,它就像添加WITH(NOLOCK)表提示一样简单,如果你发现它是阻塞的,但是如果它经常运行,那么请查看索引和统计信息。

    如果此表上有大量插入,那么任何额外的索引都会影响插入性能,但它会加快更新速度。然后是索引填充因子等等。我的观点是在Sql框上进行perf调整非常复杂,并且大部分时间都需要整个图像。

    所以我建议你在这里采取一些提示,因为没有人知道你的系统以及你,你可以做出一些决定,进行实验,并从中学习!启用您的查询执行计划并查看它,看看您是否看到任何表扫描,它们是坏的,并指出缺少正确的索引,键查找也是如此。

    但是看看你在这里给出的查询并忽略任何其他因素,这就是我的建议。

    确保您的索引中包含employee_numbercourse_code的NON CLUSTERED索引。如果是Sql 2008,如果您对这两列进行了其他查询过滤,则可以添加一些包含的列,但输出其他列。至于它们应该在索引中升序还是降序取决于你,但是将它们都保留为升序。

    然后对于查询,使用@Jonathan(给你的+1!)建议,稍作修改,在表上添加一个WITH(NOLOCK)提示。这将告诉Sql优化器在读取表时不要锁定表,但是您将能够读取脏数据。通常不是问题,除非它是一个高度事务性的表,一直在进行大量的更新和插入。

    IF EXISTS(SELECT 1 FROM course_tracking WITH(NOLOCK)
    WHERE employee_number = @employee_number
          AND course_code = @course_code)
    BEGIN
         UPDATE COURSE TRACKING
    END
    ELSE
    BEGIN
         INSERT INTO COURSE TRACKING
    END
    

    另外,检查您的统计信息是否在数据库上自动更新,如果没有,请创建一个维护作业,每天更新一次,当服务器最不活跃时。使用此作为查询EXEC sp_MSForEachTable 'UPDATE STATISTICS ? WITH FULLSCAN'

    创建SQL代理作业

答案 2 :(得分:1)

如果您的查询实际上正在更新行WHERE employee_number = @employee_number AND course_code = @course_code),那么您可以尝试这种技术:

UPDATE course_tracking
SET ...
WHERE employee_number = @employee_number
  AND course_code = @course_code;
IF @@ROWCOUNT = 0
  INSERT INTO course_tracking
  ...

答案 3 :(得分:0)

如果您有SQL 2008,MERGE语法很好。 Pinal Dave有一个很好的演练http://blog.sqlauthority.com/2008/08/28/sql-server-2008-introduction-to-merge-statement-one-statement-for-insert-update-delete/

MERGE course_tracking AS c
ON c.employee_number =  @employee_number
AND c.course_code  = @course_code 
WHEN MATCHED THEN 
UPDATE STUFF
WHEN NOT MATCHED THEN
INSERT STUFF
GO