SQL SERVER 基础使用技巧
1 .编写目的
本人总结了一些实际使用中常常因为疏忽大意而出现各种意想不到的问题,本文档总结相关经验(有些并未得到验证),便于交流学习。
1 基础
1.1 char、varchar、nchar、nvarchar的区别
(1)定义:
char:固定长度,存储ANSI字符,不足的补英文半角空格。
nchar:固定长度,存储Unicode字符,不足的补英文半角空格
varchar:可变长度,存储ANSI字符,根据数据长度自动变化。
nvarchar:可变长度,存储Unicode字符,根据数据长度自动变化。
nvarchar(n) :包含 n个字符的可变长度 Unicode 字符数据。n 的值必须介于 1 与 4,000 之间。字节的存储大小是所输入字符个数的两倍。所输入的数据字符长度可以为零。
varchar[(n)]:长度为 n 个字节的可变长度且非 Unicode的字符数据。n 必须是一个介于 1 和 8,000之间的数值。存储大小为输入数据的字节的实际长度,而不是 n 个字节。所输入的数据字符长度可以为零。
注意:ANSI主要是以单字节来存储数据,一般适合英文。而我们常用的汉字需要用两个字节来存储,所以就要使用unicode的数据类型,不然读取出来的数据可能会乱码。
(2)区别:
①从存储方式上,nvarchar是按字符存储的,而 varchar是按字节存储的;
②从存储量上考虑, varchar比较节省空间,因为存储大小为字节的实际长度,而 nvarchar是双字节存储;
③在使用上,如果存储内容都是英文字符而没有汉字等其他语言符号,建议使用varchar;含有汉字的使用nvarchar,因为nvarchar是使用Unicode编码,即统一的字符编码标准,会减少乱码的出现几率;
④ 如果你做的项目可能涉及不同语言之间的转换,建议用nvarchar。
(3)优缺点:
Nvarchar优点:判断字符串的时候可以不需要考虑中英文两种字符的差别,可以避免程序中乱码的问题。
缺点:存储英文字符会增大一倍的存储空间.但是在存储代价已经很低廉的情况下,优先考虑兼容性会给你带来更多好处的,效率没有varchar高。
(4)为什么要用nvarchar?
有n前缀的,n表示Unicode字符,即所有字符都占两个字节,nchar,nvarchar
字符中,英文字符只需要一个字节存储就足够了,但汉字众多,需要两个字节存储,英文与汉字同时存在时容易造成混乱,Unicode字符集就是为了解决字符集这种不兼容的问题而产生的,它所有的字符都用两个字节表示,即英文字符也是用两个字节表示。
(5)有关var的简单介绍:
有var前缀的,表示是实际存储空间是变长的,varchar,nvarchar
所谓定长就是长度固定的,当输入的数据长度没有达到指定的长度时将自动以英文空格在其后面填充,使长度达到相应的长度;而变长字符数据则不会以空格填充,比较例外的是,text存储的也是可变长。
(6)如何使用这些类型?
如果你肯定存储的数据长度,而且不包中文的,可以选择char类型。
如果肯定存储的数据长度,但可能包括中文,可以选择nchar类型。
如果不确定存储的数据长度,存储只有英文、数字的最好用varchar
如果不确定存储的数据长度,也有可能有中文,可以选择nvarchar类型
1.2 变量赋值
查看以上语句执行结果差异,同时也需要特别注意变量@TestId未能成功赋值(即由于查询记录不存在,导致@TestId变量还是默认初始值AAAAA),在实施中经常会出现莫名奇妙问题,很多时候就是这原因导致的,特别是在写循环语句内,通过SELECT查询对变量赋值,一定需要先赋默认值(根据变量类型分别建议设置=’’或=0)。
1.3 SELECT查询
先看几个例子,大家看下查询结果是否与想想的是一致的,如下为对应创建表结构语句及表初始数据。
CREATE TABLE [dbo].[A](
[AId] [nvarchar](50) NULL,
[CName] [nvarchar](50) NULL
)
CREATE TABLE [dbo].[B](
[BId] [nvarchar](50) NULL,
[AId] [nvarchar](50) NULL,
[CValues] [nvarchar](50) NULL
)
INSERT INTO A ( AId, CName ) VALUES ('1','王XX')
INSERT INTO A ( AId, CName ) VALUES ('2','陈XX')
INSERT INTO A ( AId, CName ) VALUES ('3','李XX')
INSERT INTO B ( BId,AId, CValues ) VALUES ('B00001','1','B1')
INSERT INTO B ( BId,AId, CValues ) VALUES ('B00002','1','B2')
INSERT INTO B ( BId,AId, CValues ) VALUES ('B00003','2','B3')
u 内连接与左连接的差异:
SELECT A.*,B.* FROM A INNER JOIN B ON A.AId = B.Aid
(内连接也经常这样写:SELECT A.*,B.* FROM A,B WHERE A.AId = B.Aid )
SELECT A.*,B.* FROM A LEFT JOIN B ON A.AId = B.Aid
u 左连接带查询条件一:
ON涉及增加连接右边表的条件
SELECT A.*,B.* FROM A LEFT JOIN B ON A.AId = B.AId
SELECT A.*,B.* FROM A LEFT JOIN B ON A.AId = B.AId AND B.CValues='B3'
左表A数据都有,右表B数据只有满足B.Cvalues是B3的才有数据,其他为null。相当于只关联符合B.Cvalues=’B3’的B,其他为null,得到的结果。
u 左连接带查询条件二:
ON涉及连接左边表的条件。
SELECT A.*,B.* FROM A LEFT JOIN B ON A.AId=B.AId AND A.CName=''
SELECT A.*,B.* FROM A LEFT JOIN B ON A.AId=B.AId AND A.CName='王XX'
SELECT A.*,B.* FROM A LEFT JOIN B ON A.AId=B.AId AND A.CName='陈XX'
始终记住left join,左表A数据都有,如果加入左表A条件CName='王XX',则只有满足A. CName='王XX',对应的右表B. AId为A. CName='王XX'对应AId的才有数据,其他为null。相当于只关联符合A. CName='王XX'的AId,其他为null,得到的结果。
u ON与WHERE过滤差异:
SELECT A.*,B.* FROM A LEFT JOIN B ON A.AId = B.AId AND B.CValues='B3'
SELECT A.*,B.* FROM A LEFT JOIN B ON A.AId = B.AId WHERE B.CValues='B3'
u 其他:
对表连接查询,所有字段都必须指定对应表名,不然会到后续表变更涉及相同字段时执行语句就出问题。表名很长可以增加对应别名,如:
SELECT B.BoxSN,A.CreateDate
FROM Lot A,WW_RMInventory B
WHERE A.LotSN='1' AND A.LotSN=B.LotSN
1.4 INSERT INTO
代码中INSERT语句必须写出全部列名(禁止不写列名的写法),以保证表增加删除字段后语句执行不受影响。
如:INSERT INTO TAB (COL1,COL2) VALUES (COL1_VAL,COL2_VAL);。
1.5 WHERE
WHERE查询条件先后顺序不同影响到执行效率。查询字段尽可能基于索引字段。
如我们对Lot表做查询操作:
SELECT *
FROM Lot
WHERE LotId='LOT1000196XG' AND ProductId='PRD10002HHWA'
/*
在都建有单个字段索引的情况下,优于下面语句,
因为通过LotId=' LOT1000196XG '第一条件过滤后的数据行少*/
SELECT *
FROM Lot
WHERE ProductId='PRD10002HHWA' AND LotId='LOT1000196XG'
1.6 NULL
建议对可能为空的字段设置默认值,这样就不会导致后续查询的不方便。
1.7 ORDER BY
ORDER BY子句的性能取决于参与排序操作的数据量多少(排序操作会在数据筛选完以后,对筛选出的结果集进行排序)。因此尽量减少返回数据。
1.8 游标与WHILE
对于循环次数较多场景下,不建议使用游标,可用其他循环如WHILE代替,因为游标相对执行耗时更长。
1.9 索引
索引的正确使用
合理的使用正确的索引是提高系统执行效率的关键因素,对索引的使用需要注意以下一些问题:
u 过度索引
一般情况下,使用索引可以缩短查询语句的执行时间,提高系统的执行效率,但是要避免过度索引的情况出现,对一个表建立了过多的索引,从而造成维护索引所需要的时间超过使用索引所降低的时间,从而造成整个系统效率的下降,这一般发生在对一些进行大量更新的表上面。
u 复合索引
复合索引是使用多个数据列的索引,第一个字段的数据区分度非常重要,也是影响一个联合索引效率的关键所在。
1.10 索引失效
u LIKE运算符
LIKE尽量前端匹配,在应用程序中为了使用方便,对字符型变量进行比较时经常使用LIKE运算符进行字符模式的匹配。需要注意的是对于LIKE运算,如果通配符%出现在字符串的尾部或中间,LIKE运算符将可以使用索引进行字符串的匹配,否则如果通配符%出现在字符串的开始,则LIKE必须使用全表扫描的方式去匹配字符串,这将产生较大的系统负荷。一般情况下,为了提高系统的效率,我们希望用户能够在通配符的左端提供较多的数据信息以降低查询的数量。
u 条件中不要使用函数
不要对有索引的字段使用任何计算,包括函数。因为这会导致无法使用索引进行数据检索,从而导致扫描(全表)操作。
SELECT LotId,LotSN,CreateDate
FROM Lot
WHERE DATEDIFF(DD,CreateDate,'2010-08-09 12:30:30')>=0
修改为:
SELECT LotId,LotSN,CreateDate
FROM Lot
WHERE '2010-08-09 12:30:30'>=CreateDate
还有其他函数等等:
select id from t where substring(name,1,3)='abc'
u 避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。
select id from t where num/2=100
修改为:
select id from t where num=100*2
u 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描(有的资料说is null不会导致索引失效),如:
select id from t where num is null
可以在num上设置默认值0或'',确保表中num列没有null值,然后这样查询:
select id from t where num=0
select id from t where num= ''
u 其他
尽量不要使用!= 或“<>”
尽量避免使用OR
尽量避免使用in 和 not in
u 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。
1.11 SQL优化
避免使用复合SQL语句(如:SELECT A,B FROM TABLE1 WHERE A IN (SELECT A1 FROM TABLE2))
尽量避免使用DISTINCT
不要在存储过程或函数中反复访问同一张表,如果需要,可以将数据放在临时表中使用。
如果能从一条SQL语句中获取多个想要的数据,就不要分多条SQL语句分分次获取
使用EXISTS代替IN,NOT EXISTS 代替NOT IN
查询的WHERE过滤原则,应使过滤记录数最多的条件
多表连接查询时,可以先按条件过滤在进行连接
select、insert子句的代码中不允许出现“*”以代替查询所有字段,必须用实际的字段名代替
提高GROUP BY的执行效率,在进行GROUP BY 之前将不需要条件过滤掉
尽量使用“>=” “<=”不要使用“>” “<”。
2 技巧
1.12 查找存储过程被哪些存储过程调用
select distinct name
from syscomments a,sysobjects b
where a.id=b.id and b.xtype='p' and text like '%被调用存储过程名%'
1.13 查找表被哪些存储过程调用
select distinct object_name(id) from syscomments
where id in(select id from sysobjects where type ='P') and text like '%DCMoveStationKN%'
1.14 日期相关


--本周的第一天 SELECT DATEADD(wk, DATEDIFF(wk,0,getdate()), 0) --本年的第一天 SELECT DATEADD(yy, DATEDIFF(yy,0,getdate()), 0) --本季度的第一天 SELECT DATEADD(qq, DATEDIFF(qq,0,getdate()), 0) --当天的凌晨 SELECT DATEADD(dd, DATEDIFF(dd,0,getdate()), 0) --上个月的最后一天 SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)) --上一年的最后一天 SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)) --本月的第一天 SELECT DATEADD(mm, DATEDIFF(mm,0,getdate()), 0) --本月的最后一天 SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0)) --本年的最后一天 SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate())+1, 0)) --本月的第一个星期一 select DATEADD(wk, DATEDIFF(wk,0, dateadd(dd,6-datepart(day,getdate()),getdate())), 0) Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AM Select CONVERT(varchar(100), GETDATE(), 1): 05/16/06 Select CONVERT(varchar(100), GETDATE(), 2): 06.05.16 Select CONVERT(varchar(100), GETDATE(), 3): 16/05/06 Select CONVERT(varchar(100), GETDATE(), 4): 16.05.06 Select CONVERT(varchar(100), GETDATE(), 5): 16-05-06 Select CONVERT(varchar(100), GETDATE(), 6): 16 05 06 Select CONVERT(varchar(100), GETDATE(), 7): 05 16, 06 Select CONVERT(varchar(100), GETDATE(), 8): 10:57:46 Select CONVERT(varchar(100), GETDATE(), 9): 05 16 2006 10:57:46:827AM Select CONVERT(varchar(100), GETDATE(), 10): 05-16-06 Select CONVERT(varchar(100), GETDATE(), 11): 06/05/16 Select CONVERT(varchar(100), GETDATE(), 12): 060516 Select CONVERT(varchar(100), GETDATE(), 13): 16 05 2006 10:57:46:937 Select CONVERT(varchar(100), GETDATE(), 14): 10:57:46:967 Select CONVERT(varchar(100), GETDATE(), 20): 2006-05-16 10:57:47 Select CONVERT(varchar(100), GETDATE(), 21): 2006-05-16 10:57:47.157 Select CONVERT(varchar(100), GETDATE(), 22): 05/16/06 10:57:47 AM Select CONVERT(varchar(100), GETDATE(), 23): 2006-05-16 Select CONVERT(varchar(100), GETDATE(), 24): 10:57:47 Select CONVERT(varchar(100), GETDATE(), 25): 2006-05-16 10:57:47.250 Select CONVERT(varchar(100), GETDATE(), 100): 05 16 2006 10:57AM Select CONVERT(varchar(100), GETDATE(), 101): 05/16/2006 Select CONVERT(varchar(100), GETDATE(), 102): 2006.05.16 Select CONVERT(varchar(100), GETDATE(), 103): 16/05/2006 Select CONVERT(varchar(100), GETDATE(), 104): 16.05.2006 Select CONVERT(varchar(100), GETDATE(), 105): 16-05-2006 Select CONVERT(varchar(100), GETDATE(), 106): 16 05 2006 Select CONVERT(varchar(100), GETDATE(), 107): 05 16, 2006 Select CONVERT(varchar(100), GETDATE(), 108): 10:57:49 Select CONVERT(varchar(100), GETDATE(), 109): 05 16 2006 10:57:49:437AM Select CONVERT(varchar(100), GETDATE(), 110): 05-16-2006 Select CONVERT(varchar(100), GETDATE(), 111): 2006/05/16 Select CONVERT(varchar(100), GETDATE(), 112): 20060516 Select CONVERT(varchar(100), GETDATE(), 113): 16 05 2006 10:57:49:513 Select CONVERT(varchar(100), GETDATE(), 114): 10:57:49:547 Select CONVERT(varchar(100), GETDATE(), 120): 2006-05-16 10:57:49 Select CONVERT(varchar(100), GETDATE(), 121): 2006-05-16 10:57:49.700 Select CONVERT(varchar(100), GETDATE(), 126): 2006-05-16T10:57:49.827 Select CONVERT(varchar(100), GETDATE(), 131): 18/04/1427 10:57:49:920AM
SQL SERVER 基础使用技巧的更多相关文章
- SQL server基础知识(表操作、数据约束、多表链接查询)
SQL server基础知识 一.基础知识 (1).存储结构:数据库->表->数据 (2).管理数据库 增加:create database 数据库名称 删除:drop database ...
- 数据库开发基础-SQl Server 基础
SQL Server 基础 1.什么是SQL Server SQL:Structured Query Language 结构化查询语言 SQL Server是一个以客户/服务器(c/s)模式访问.使 ...
- 【SQL Server】SQL Server基础之存储过程
SQL Server基础之存储过程 阅读目录 一:存储过程概述 二:存储过程分类 三:创建存储过程 1.创建无参存储过程 2.修改存储过程 3.删除存储过程 4.重命名存储过程 5.创建带参数的存储 ...
- Sql Server 基础知识
Sql Server 基础知识: http://blog.csdn.net/t6786780/article/details/4525652 Sql Server 语句大全: http://www.c ...
- MS SQL Server数据库查询优化技巧
[摘 要]本文主要是对MS SQL Server数据库查询优化技巧进行了说明和分析,对索引使用.查询条件以及数据表的设计等进行了阐述.中国论文网 http://www.xzbu.com/2/view- ...
- Sql Server 基础语法
来自:http://www.cnblogs.com/AaronYang/archive/2012/04/24/2468093.html Sql Server 基础语法 -- 查看数据表 select ...
- 《SQL Server基础——SQL语句》
SQL Server基础--SQL语句 一.创建和删除数据库: 1.创建数据库(默认化初始值) 格式: CREATE DATABASE 数据库名称 例如: CREATE DATABASE ...
- Sql的基础知识技巧(三)
三.技巧 1.1=1,1=2 的使用,在 SQL 语句组合时用的较多 "where 1=1" 是表示选择全部 "where 1=2"全部不选, 如:if @st ...
- 【SQL server】SQL server基础(二)
一.一些重要的SQL命令 SELECT - 从数据库中提取数据 UPDATE - 更新数据库中的数据 DELETE - 从数据库中删除数据 INSERT INTO - 向数据库中插入新数据 CREAT ...
- SQL Server基础之索引
索引用于快速找出在某个列中有某一特定值的行,不使用索引,数据库必须从第一条记录开始读完整个表,直到找出相关的行.表越大,查询数据所花费的时间越多,如果表中查询的列有一个索引,数据库能快速到达一个位置 ...
随机推荐
- Linux搭建docker
### 1. 查看系统的内核版本 ```bash[root@wide ~]# uname -r3.10.0-1160.el7.x86_64``` ### 2. 将yum更新到最新版本 ```bash[ ...
- 【Java Se】JDBC
启停服务 net start mysql net stop mysql 登录 mysql -u -p 访问指定IP的mysql mysql -u root -P 3306 -h localhost - ...
- KB5024276 - SQL Server 2019 的累积更新 20
发布日期: 2023/4/13 版本: 15.0.4312.2 摘要 此更新中的已知问题 此更新包括的改进和修补程序 如何获取或下载此或最新的累积更新包 文件信息 此更新注意事项 如何卸载此更新 参考 ...
- Kubernetes集群调度增强之超容量扩容
作者:京东科技 徐宪章 1 什么是超容量扩容 超容量扩容功能,是指预先调度一定数量的工作节点,当业务高峰期或者集群整体负载较高时,可以使应用不必等待集群工作节点扩容,从而迅速完成应用横向扩容.通常情况 ...
- Solon2 常用注解之 @ProxyComponent 用法说明
在 Solon 提倡"克制"的原则下,托管组件分为: 普通组件 代理组件(即 @ProxyComponent 注解的类).代理的细节可以看下<动态代理的本质> . 之所 ...
- 10分钟带你徒手做个Java线程池
摘要:花10分钟开发一个极简版的Java线程池,让小伙伴们更好的理解线程池的核心原理. 本文分享自华为云社区<放大招了,冰河带你10分钟手撸Java线程池,yyds,赶快收藏吧>,作者:冰 ...
- 利用Velero对K8S备份还原与集群迁移实战
一.简介 Velero 是一款云原生时代的灾难恢复和迁移工具,采用 Go 语言编写,并在 github 上进行了开源,利用 velero 用户可以安全的备份.恢复和迁移 Kubernetes 集群资源 ...
- javasec(六)RMI
这篇文章介绍java-RMI远程方法调用机制. RMI全称是Remote Method Invocation,远程⽅法调⽤.是让某个Java虚拟机上的对象调⽤另⼀个Java虚拟机中对象上的⽅法,只不过 ...
- 一文详解RocketMQ-Spring的源码解析与实战
摘要:这篇文章主要介绍 Spring Boot 项目使用 rocketmq-spring SDK 实现消息收发的操作流程,同时笔者会从开发者的角度解读 SDK 的设计逻辑. 本文分享自华为云社区< ...
- Centos7.x 安装jenkins
一.安装 前提:需查看是否安装了JDK 1.第一种方法 sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat ...