2011-02-15 107 views
0

我有了在存储过程下面的SQL查询的ASP.NET应用程序:的SQL Server存储过程的性能

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表中有将近一百万行和SQL事件探查器显示40K之间每执行一次这个过程几秒钟就读取50k。

因为我不是一个SQL Server性能测试的家伙...什么是最好的方法来纠正?

任何帮助,非常感谢。

感谢

+1

确保`course_code`和`employee_number`都编入索引。覆盖指数应该可以正常工作。 – JNK 2011-02-15 20:28:07

+3

什么是SQL Server版本?因为SQLServer 2008为你提供了`MERGE`能力,这对于这样的upserts来说非常棒。 – Matthew 2011-02-15 20:30:16

+0

@JNK,他不需要包括计数的id列吗? – DForck42 2011-02-15 20:37:31

回答

1

亚历克斯,

可以有许多原因的大量阅读,而且我相信,@乔纳森的回答将帮助,或者掩盖了问题,现在。获得大量读取的原因将是因为您缺少一些关键索引,并且/或者您的表统计信息不是最新的,或者它已关闭。

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

  1. 如何经常是这样的查询运行
  2. 当它运行的它的系统
  3. 什么是这个最频繁的操作 上影响其他进程表,插入或更新?

如果这个查询每天运行一次,或者很少发生,并且不影响其他进程,我可能会倾向于离开它。但是,如果这是一个运行频繁和/或影响其他进程的进程,那么您需要修复它。现在通过修复它,它可以很简单,只要添加WITH(NOLOCK)表提示,如果您发现它阻塞,但如果它运行频繁,然后查看索引和统计信息。

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

所以我建议你在这里提一些提示,因为没有人知道你的系统和你一样,你可以做出一些决定,并做实验,并从中学习!启用您的查询执行计划并查看它,看看是否有任何表扫描,它们不好,并且表明缺少适当的索引,关键查找也是如此。

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

确保索引中包含employee_numbercourse_code的非聚簇索引。如果是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'

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 
0

如果你有SQL 2008年,MERGE语法是好的。皮纳尔戴夫具有良好的演练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 
+0

语法都很好,但没有合适的索引和糟糕的表格设计,这只会掩盖问题,如果它会掩盖它。 – Ryk 2011-02-15 21:58:15

1

创建一个SQL代理作业如果查询实际更新的行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 
    ...