您的位置:首页 > 数据库 > 其它 > 正文

SQL Server批处理注意的事项

更多 时间:2014-5-11 类别:数据库 浏览量:480

SQL Server批处理注意的事项

SQL Server批处理注意的事项

一、为了将一个脚本分为多个批处理,可以使用GO语句

1. GO语句必须自成一行。

2. GO语句使得每个批处理是单独发送到服务器的,与其他的批处理器无关。(这里面的执行方案很可能是并发的,所以在很多的情况下,可能需要考虑顺序问题)

3. GO语句不是T-sql命令,而是由各种SQLServer命令适用成型的识别命令。

 

二、批处理编译错误或者运行错误对数据库的影响
 
假设现在有一个批处理语句,其中有五条T-SQL语句。这个批处理语句传递到SQL Server数据库之后,数据库系统会先对这个语句进行编译。如果编译错误那么对数据库会有什么影响呢?通常情况下,由于语法错误等因素导致的编译错误会使得可执行计划无法编译。也就是说,此时这个批处理语句中的任何语句都得不到执行。故在批处理语句编译错误的情况下,基本上不会对数据库产生任何影响。
 
如果批处理程序编译通过,但是在执行的过程中出现了问题,那么又会对数据库产生什么影响呢?如上面所说的一个批处理程序有五条语句,编译通过后,如果在执行过程中由于一些意外原因导致第三条语句执行失败,此时会对数据库产生什么样的影响?此时就需要根据不同的情况来对待。如果这个错误是因为违反约束所造成的,那么批处理程序仅仅停止执行当前语句,而继续执行批处理中的其他语句。也就是说,由于违反约束而导致批处理程序运行错误的话,那么只影响那条违反约束规则等语句,前面的与后面的语句仍然将得以执行。针对于数据库管理员可能是不喜欢看到的,因为这会破坏数据的一致性。除了违反约束这种情况外,大部分情况下运行时错误将停止执行批处理中当前语句和它之后的其他语句。也就是说,如果在执行第三条语句时发生了错误,则其后面的语句都将不执行。但是其前面已经执行的语句将不受到影响。
 
可见无论是违反约束这种错误情况,还是其他的错误情况,当遇到错误时,都有可能批处理中某些语句得到了有效的执行。这往往与数据库管理员或者应用程序开发者的设计意图相悖。因为他们之所以要设计这个批处理程序,往往是让它来实现一整套的功能。如果数据库无法实现这个功能的话,那么他们宁愿一条语句的不执行。如果只执行部分语句的话,会对数据库的一致性产生比较大的负面影响。为了保证批处理程序在遇到错误时,无论是什么错误,都不会对数据库造成负面影响,此时笔者建议数据库管理员或者程序开发者把批处理程序跟事务结合起来使用。也就是说,将批处理程序放置在事务中。如此的话,当批处理程序在运行的过程中遇到错误的话,会导致事务会滚。如此的话,在所有运行的错误之前执行的未提交的数据修改都将被回滚。这就可以避免因为批处理程序运行错误而导致的数据损坏问题。

 

三、批处理中的错误

 

1. 语法错误,在执行之前就会被检测。

2. 运行时错误,只能在运行之后(或者之中)被检测到,一般是违反了完整性等错误。

 

要求有自己批处理的语句

1. Create Default

2. Create Procedure

3. Create Rule

4. Create Trigger

5. Create View

注:如果想在单独的脚本中将这些语句组合,则需要通过使用GO语句来将它们分散到各自的批处理中。

 

四、养成以分号结束语句的习惯
 
在编写批处理程序时,最好能够以分号结束相关的语句。虽然这不是数据库中的强制要求,但是笔者还是强烈建议如此处理。一方面这有利于提高批处理程序的可读性。批处理程序往往用来完成一些比较复杂的成套的功能,而每条语句则完成一项独立的功能。为此有时会一个比较复杂一些的批处理程序其往往有上百行的内容。此时为了提高其可读性,最好能够利用分号来进行语句与语句之间的分隔。二是与未来版本的兼容性。其实SQL Server数据库在设计的时候,一开始这方面就把关不严。现在大部分的标准程序编器都实现了类似的强制控制。根据宪梓微软官方提供的资料来看,在以后的SQL Server数据库版本中,这个规则可能会成为一个强执行的规则,即必须在每条语句后面利用分号来进行分隔。为此为了能够跟后续的SQL Server数据库版本进行兼容,最好从现在开始就采用分号来分隔批处理程序中的每条语句。


 
五、批处理程序语句所处理对象不存在或不符合会如何处理?
 
如现在某个批处理程序中有五条语句,其中第一条语句是创建表User,第三条语句是往表User中插入数据(插入的数据与第一条语句中定义的数据类型不符合)。当应用程序把这个批处理程序发给SQL Server数据库的时候,系统会对这个批处理对象进行编译。注意此时只是编译,而没有执行。编译只要语法没有错误即可。最后这个批处理程序会被编译成功,但是没有执行,即没有创建User表。编译完成后,这个批处理程序会运行。第一条语句编译后运行没有错误,但是运行到第二条语句的时候由于需要插入的数据跟第一条语句中所建立的数据库对象不符合,则第三条语句会编译失败。此时批处理终止。笔者举这个例子是为了说明2008数据库版本的一个改善,即对于批处理程序中的语句,数据库是编译一条,而执行一条。
 
假设这个批处理程序若放在2000版本的SQL Server数据库中,就会出现一个截然不同的结果。由于在2000版本中,对于批处理程序都是整篇编译的。此时在编译的时候就会发现这个对象不符的错误。具体哪一种处理机制好也是各人各有各的看法。笔者还是比较倾向于以前版本的处理方法,即整篇编译。这虽然可能会影响数据库的性能,但是影响不会很大;但是却可以提高批处理程序的正确性。或者说,由此带来的性能方面的损失,可能要比由此对来的对数据库数据的破坏性损失要小的多。不过在这方面各个数据库专家谁也说服不了谁。


 
五、批处理程序书写的一些限制要求
 
由于批处理程序中往往需要完成一整套的功能。而且一旦批处理程序开始运行时,就会缺少用户的监督。或者说,互动性会比较差。为此如何保障批处理程序语句的有效性就显得尤其的重要。为此在书写批处理程序时,数据库设置了一些严格的规范。这些规范跟上面所提高的利用分号来分隔批处理程序语句不同。这里提到的规范具有强制性,即为反这个规则的话将会发生变异错误,批处理程序得不到执行。而上面提到的分号规则不具有强制性,其编辑时不会发生语法性错误,在没有其他错误的情况下可以正常执行这个批处理语句。
 
如不能够在同一个批处理中更改表,然后引用新列。如在一个批处理程序中,有两条语句。第一条语句用来在一张表中插入一个字段,如在User表中插入员工的出生年月;第二条语句则用来引用这个列,如根据身份证号码来推算出这个员工的出身年月并把这个值赋值给这个第一条语句创建的出身年月字段。这个批处理程序是非法的。因为在第一条语句中其引用了第一条语句创建的新列。这是批处理文件书写中的一条红线,不得违背。但是注意,如果第一条语句不是增加了某个列,而是通过创建表的方式来创建列,那么后面的语句就可以引用这些列。也就说,如果第一条语句创建了一个表User,其中有出身年月这个字段。则在第二条语句中就可以利用这个出身年月字段,如可以利用insert语句为其进行赋值。这个细小的差异要引起数据库管理员的注意。
 
通常情况下,一个批处理程序可以包含多条语句。但是在一些特定的情况下会有例外。如果在批处理程序中包含了一些特殊的语句,则此时批处理程序中之能够包含一条语句。如在批处理文件中利用Create View语句创建视图时,就不能够与其他语句组合使用。此时所有跟在该批处理后的其他语句都将被解释为第一个Create语句定义的一部分。另外需要注意的是,如果 EXECUTE 语句是批处理中的第一句,则不需要 EXECUTE 关键字。如果 EXECUTE 语句不是批处理中的第一条语句,则需要 EXECUTE 关键字。

 

六、EXEC的陷阱

1. Exec和调用它的代码都在单独的作用域下运行——也就是说,调用代码不能引用EXEC语句中的变量,并且在调用代码中的变量被解析为用于EXEC语句的字符串之后,EXEC不能引用这些变量。如果需要在动态SQL和调用它的例程间传递值,考虑使用SQL-executeSQL。

2. 默认情况下,EXEC在当前用户的安全上下文下运行——而不是调用对象的安全上下文。(对象经常在对象所有者的上下文运行,而不是当前用户)

3. EXEC与调用对象运行在相同的连接和事务环境下。

4. 对EXEC字符串执行的要求函数调用的串联必须先于实际调用的EXEC的语句——不能在执行EXEC调用的相同语句中执行函数串联。

5. EXEC不能再用户自定义函数内使用。

 

七、批处理总结

 

1、一个批处理中只要存在一处语法错误,整个批处理都无法通过编译。

  • 2、批处理中可以包含多个存储过程,但除第一个过程外,其他存储过程前面都必须使用EXECTUE关键字。
  •  
  • 3、某些特殊的SQL指令不能和别的SQL语句共存在一个批处理中,如CREATETABLE和CREATEVIEW语句。这些语句只能独自存在于一个单独的存储过程中。
  •  
  • 4、所有的批处理使用GO作为结束的标志,当编译器读到GO的时候就把GO前面的所有语句当成一个批处理,然后打包成一个数据包发给服务器。
  •  
  • 5、GO本身不是T-SQL的组成部分,只是一个用于表示批处理结束的前端指令。
  •  
  • 6、不能在删除一个对象之后,在同一批处理中再次引用这个对象。
  •  
  • 7、如果EXECUTE语句是批处理中的第一句,则不需要EXECUTE关键字。如果EXECUTE语句不是批处理中的第一条语句,则需要EXECUTE关键字。
  •  
  • 8、不能在定义一个CHECK约束之后,在同一个批处理中使用。
  •  
  • 9、不能在修改表的一个字段之后,立即在同一个批处理中引用这个字段。
  •  
  • 10、使用SET语句设置的某些选项值不能应用于同一个批处理中的查询。
  •