[20141114]这些年你需要注意的SQL
#1、使用对象时,请显式的指定对象的架构者(默认为dbo)
分析:在SQL SERVER中,如果用户User1访问表table1,那么查询分析器必须决定是检索 User1.table1 还是 dbo.table1 。所以每次User1访问同一张表table1时,查询分析器都必须对查询计划 重编译,影响执行速度。
#2、尽量避免使用SELECT *,建议使用 SELECT
分析:采用SELECT * 语法会导致DB对列进行一个遍历,同时可能会查询多余字段数据(本着用啥查啥的原则,建议使用SELECT <Field List>),导致查询性能下降。
#3、如果一个T-SQL语句涉及到多个表,则引用的每个列必须制定该列所属的对象
分析:避免造成数据查询异常
#4、Insert语句中必须指定插入列的列表
分析:避免表列变化导致插入语句失败
#5、在非事物和特别要求完整性的上下文中,使用NOLOCK查询
分析:考虑到并发性,提高查询效率
示例:
SELECT TOP 100 COL1,COL2 FROM TABLE1 t1 WITH (NOLOCK)
#6、通过SELECT语句对变量赋值时,如果未使用聚合函数,请加上TOP 1
分析:防止结果非预期
示例:(预期结果为2,因为第二次Name2是后添加的。)
CREATE TABLE test6
(
Id int
,Name nvarchar(32)
)
INSERT INTO test6 (Id, Name)
SELECT 1, N'Name1'
UNION all
SELECT 2, N'Name2'
INSERT INTO test6 (Id, Name)
SELECT 3, N'Name2'
--错误的写法
DECLARE @Id int
SELECT
@Id=Id
FROM test6
WHERE
Name = 'Name2'
--正确的写法
DECLARE @Id int
SELECT TOP 1
@Id=Id
FROM test6
WHERE
Name = 'Name2'
#7、对于排序后取字段TOP 1的值,建议使用聚合
分析:可以用上索引,而且不需要Table Scan
示例:
--错误的写法
SELECT TOP 1 col1 FROM table1 ORDER BY col1 DESC
--正确的写法
SELECT MAX(col1) FROM table1
#8、有关char和varchar,char和nchar,varchar和nvarchar的区别
分析:
- char是固定长度,如果数据不够,会在存储时自动补空格
- varchar是可变长度,会有三个字节来存储字段信息,可以设置最大长度
- nchar和varchar这种以N开头的表示存储unicode编码字符
- 在特定字符集下,如果定义数据格式为char或者是varchar,那么存储特殊字符(包括中文)会乱码
- 关于数据库函数LEN(),是用于返回指定字符串表达式的字符数,其中不包含尾随空格。
- 关于DATALENGTH函数,返回用于表示任何表达式的字节数。
示例:
DECLARE @s1 CHAR(5)
,@s2 VARCHAR(5)
,@s3 NCHAR(5)
,@s4 NVARCHAR(5)
--看看这个结果是什么?
SET @s1 = 'test'
SET @s2 = 'test'
SET @s3 = 'test'
SET @s4 = 'test'
SELECT
LEN(@s1)
,LEN(@s2)
,LEN(@s3)
,Len(@s4)
SELECT
DATALENGTH(@s1)
,DATALENGTH(@s2)
,DATALENGTH(@s3)
,DATALENGTH(@s4)
--如果这样呢?
SET @s1 = '我是中文'
SET @s2 = '我是中文'
SET @s3 = '我是中文'
SET @s4 = '我是中文'
SELECT
LEN(@s1)
,LEN(@s2)
,LEN(@s3)
,Len(@s4)
SELECT
DATALENGTH(@s1)
,DATALENGTH(@s2)
,DATALENGTH(@s3)
,DATALENGTH(@s4)
--一般情况下,SELECT @s1,@s2,@s3,@s4不会显示乱码,是由于安装SQL SERVER的时候后默认字符集是支持unicode字符的。如果遇到不支持的字符集,就需要显示定义字段类型为带N的类型,同时在赋值的时候使用N'中文'这种形式。
#9、禁止在使用了事物的情况下,不编写防止造成未提交或者未回滚事务的情况的处理代码
分析:数据库阻塞,你懂的...罪过大大的!
#10、警惕表变量的使用
示例:
--思考下结果是什么?
IF NOT exists (SELECT 1)
BEGIN
PRINT 'enter'
DECLARE @table TABLE
(
name nvarchar(32)
)
END
SELECT name FROM @table
分析:
- 在表变量的使用中,会出现如JavaScript一样的定义前置,相当于不管你在哪个条件(也不关心是否能走到这个分支)中定义表变量,那么这个表变量在整个作用域中都是有效的。
- 临时表表现正常
- 表变量和一般的变量有点不一样的地方,表变量也会在tempdb中创建表。示例如下:
CREATE TABLE #TempTable (TT_Col1 INT)
DECLARE @TableVariable TABLE (TV_Col1 INT)
SELECT TOP 2 *
FROM tempdb.sys.tables
ORDER BY create_date DESC
#11、判断是否存在(或者不存在)符合条件的记录使用 EXISTS 关键字。
分析:
IF (SELECT COUNT(*) FROM Table WITH (NOLOCK))>0
BEGIN
--Do something
END
--应该用:
IF EXISTS(SELECT TOP 1 1 FROM Table WITH (NOLOCK)
BEGIN
--Do something
END
#12、字符串比较时,SQL SERVER会忽略末尾的空格。
示例:
SELECT 1
WHERE 't' ='t '
#13、注意NULL的特殊性
分析:
1.NULL既不能被=匹配,也不能被<>(!=)匹配,只能用IS NULL 或者是 ISNULL()
示例:
CREATE TABLE #tb(col1 int)
INSERT INTO #tb(col1)
SELECT NULL
UNION
SELECT 1
UNION
SELECT 2
SELECT COUNT(*) FROM #tb
WHERE col1 <> 1 OR col1 = 1 --2
SELECT COUNT(*) FROM #tb --3
14、COUNT(0),COUNT(*),COUNT(column)的区别
分析:
- COUNT(0),COUNT(*)计数时会包含NULL值
- COUNT(column)计数时,如果需要该列为NULL,则会忽略计数
示例:
CREATE TABLE #tb(col1 int)
INSERT INTO #tb(col1)
SELECT NULL
UNION
SELECT 1
UNION
SELECT 2
SELECT COUNT(*) FROM #tb --3
SELECT COUNT(0) FROM #tb --3
SELECT COUNT(col1) FROM #tb --2
#15、通过合理的方法避免在 SELECT 语句中使用 DISTINCT
分析:
- DISTINCT 是数据查询中一个非常慢的操作,所以尽可能的避免
示例:
SELECT DISTINCT
A.au_fname
,A.au_lname
FROM dbo.authors AS A WITH (NOLOCK)
INNER JOIN dbo.titleAuthor AS T WITH (NOLOCK) --一对多的关系
ON T.au_id = A.au_id
--避免DISTINCT的写法
SELECT au_fname
,au_lname
FROM dbo.authors AS A WITH (NOLOCK)
WHERE EXISTS (
SELECT TOP 1 1
FROM dbo.titleAuthor AS T WITH (NOLOCK)
WHERE T.au_id = A.au_id