Skip to content

Latest commit

 

History

History
268 lines (203 loc) · 6.31 KB

[20141114]这些年你需要注意的SQL.md

File metadata and controls

268 lines (203 loc) · 6.31 KB
title date
这些年你需要注意的SQL
2014/11/14 00:00:00

#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的区别

分析:

  1. char是固定长度,如果数据不够,会在存储时自动补空格
  2. varchar是可变长度,会有三个字节来存储字段信息,可以设置最大长度
  3. nchar和varchar这种以N开头的表示存储unicode编码字符
  4. 在特定字符集下,如果定义数据格式为char或者是varchar,那么存储特殊字符(包括中文)会乱码
  5. 关于数据库函数LEN(),是用于返回指定字符串表达式的字符数,其中不包含尾随空格。
  6. 关于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

分析:

  1. 在表变量的使用中,会出现如JavaScript一样的定义前置,相当于不管你在哪个条件(也不关心是否能走到这个分支)中定义表变量,那么这个表变量在整个作用域中都是有效的。
  2. 临时表表现正常
  3. 表变量和一般的变量有点不一样的地方,表变量也会在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)的区别

分析:

  1. COUNT(0),COUNT(*)计数时会包含NULL值
  2. 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

分析:

  1. 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