点击上方SQL数据库开发,关注获取SQL视频教程
SQL专栏
我们做软件开发的,大部分人都离不开跟数据库打交道,特别是erp开发的,跟数据库打交道更是频繁,存储过程动不动就是上千行,如果数据量大,人员流动大,那么我么还能保证下一段时间系统还能流畅的运行吗?我么还能保证下一个人能看懂我么的存储过程吗?那么我结合公司平时的培训和平时个人工作经验和大家分享一下,希望对大家有帮助。
要知道sql语句,我想我们有必要知道sqlserver查询分析器怎么执行我么sql语句的,我么很多人会看执行计划,或者用profile来监视和调优查询语句或者存储过程慢的原因,但是如果我们知道查询分析器的执行逻辑顺序,下手的时候就胸有成竹,那么下手是不是有把握点呢?
一、查询的逻辑执行顺序
--如有表table1(ID,col1)和table2 (ID,col2)
Select A.ID, A.col1, B.col2
-- Select A.ID, col1, col2 –不要这么写,不利于将来程序扩展
from table1 A inner join table2 B on A.ID=B.ID Where …
B、纵向来看
(1)合理写WHERE子句,不要写没有WHERE的SQL语句。
(2) SELECT TOP N * --没有WHERE条件的用此替代
UPDATE EMPLOYEE SET FNAME='HAIWER'
WHERE EMP_ID=' VPA30890F'
UPDATE EMPLOYEE SET LNAME='YANG'
WHERE EMP_ID=' VPA30890F'
UPDATE EMPLOYEE SET FNAME='HAIWER',LNAME='YANG'
WHERE EMP_ID=' VPA30890F'
五、注意临时表和表变量的用法
SELECT PUB_NAME FROM PUBLISHERS
WHERE PUB_ID NOT IN
(SELECT PUB_ID FROM TITLES
WHERE TYPE = 'BUSINESS')
--可以改写成:
SELECT A.PUB_NAME FROM PUBLISHERS A
LEFT JOIN TITLES B ON B.TYPE = 'BUSINESS' AND A.PUB_ID=B. PUB_ID
WHERE B.PUB_ID IS NULL
(2)
SELECT TITLE FROM TITLES
WHERE NOT EXISTS
(SELECT TITLE_ID FROM SALES
WHERE TITLE_ID = TITLES.TITLE_ID)
可以改写成:
SELECT TITLE
FROM TITLES
LEFT JOIN SALES ON SALES.TITLE_ID = TITLES.TITLE_ID
WHERE SALES.TITLE_ID IS NULL
SELECT PUB_NAME FROM PUBLISHERS
WHERE PUB_ID IN
(SELECT PUB_ID FROM TITLES
WHERE TYPE = 'BUSINESS')
可以改写成:
SELECT A.PUB_NAME --SELECT DISTINCT A.PUB_NAME
FROM PUBLISHERS A
INNER JOIN TITLES B
ON B.TYPE = 'BUSINESS' AND A.PUB_ID=B. PUB_ID
(3)
C、
IN
的相关子查询用EXISTS代替,比如
SELECT PUB_NAME FROM PUBLISHERS
WHERE PUB_ID IN
(SELECT PUB_ID FROM TITLES WHERE TYPE = 'BUSINESS')
--可以用下面语句代替:
SELECT PUB_NAME FROM PUBLISHERS
WHERE EXISTS
(SELECT 1 FROM TITLES
WHERE TYPE = 'BUSINESS' AND PUB_ID= PUBLISHERS.PUB_ID)
D、不要用
COUNT
(*)的子查询判断是否存在记录,好用
LEFT
JOIN
或者EXISTS,比如有人写这样的语句:
SELECT JOB_DESC FROM JOBS
WHERE (SELECT COUNT(*) FROM EMPLOYEE
WHERE JOB_ID=JOBS.JOB_ID)=0
--应该改成:
SELECT JOBS.JOB_DESC FROM JOBS
LEFT JOIN EMPLOYEE ON EMPLOYEE.JOB_ID=JOBS.JOB_ID
WHERE EMPLOYEE.EMP_ID IS NULL
SELECT JOB_DESC FROM JOBS
WHERE (SELECT COUNT(*) FROM EMPLOYEE
WHERE JOB_ID=JOBS.JOB_ID)<>0
--应该改成:
SELECT JOB_DESC FROM JOBS
WHERE EXISTS (SELECT 1 FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)
七、尽量使用索引
SELECT ID FROM T WHERE NUM/2=100
应改为:
SELECT ID FROM T WHERE NUM=100*2
SELECT ID FROM T WHERE NUM/2=NUM1
如果NUM有索引应改为:
SELECT ID FROM T WHERE NUM=NUM1*2
如果NUM1有索引则不应该改。
SELECT 年,月,金额 FROM 结余表 WHERE 100*年+月=2010*100+10
应该改为:
SELECT 年,月,金额 FROM 结余表 WHERE 年=2010 AND月=10
日期字段的例子:
WHERE CONVERT(VARCHAR(10), 日期字段,120)='2010-07-15'
应该改为
WHERE日期字段〉='2010-07-15' AND 日期字段<'2010-07-16'
ISNULL转换的例子:
WHERE ISNULL(字段,'')<>''应改为:WHERE字段<>''
WHERE ISNULL(字段,'')=''不应修改
WHERE ISNULL(字段,'F') ='T'应改为: WHERE字段='T'
WHERE ISNULL(字段,'F')<>'T'不应修改
WHERE LEFT(NAME, 3)='ABC' 或者 WHERE SUBSTRING(NAME,1, 3)='ABC'
应改为: WHERE NAME LIKE 'ABC%'
日期查询的例子:
WHERE DATEDIFF(DAY, 日期,'2010-06-30')=0
应改为:WHERE 日期>='2010-06-30' AND 日期 <'2010-07-01'
WHERE DATEDIFF(DAY, 日期,'2010-06-30')>0
应改为:WHERE 日期 <'2010-06-30'
WHERE DATEDIFF(DAY, 日期,'2010-06-30')>=0
应改为:WHERE 日期 <'2010-07-01'
WHERE DATEDIFF(DAY, 日期,'2010-06-30')<0
应改为:WHERE 日期>='2010-07-01'
WHERE DATEDIFF(DAY, 日期,'2010-06-30')<=0
应改为:WHERE 日期>='2010-06-30'
比如:
WHERE FAME+ '. '+LNAME='HAIWEI.YANG'
应改为:
WHERE FNAME='HAIWEI' AND LNAME='YANG'
八、多表连接的连接条件对索引的选择有着重要的意义,所以我们在写连接条件条件的时候需要特别注意。
考虑联接优先顺序:
(1)INNER JOIN
(2)LEFT JOIN (注:RIGHT JOIN 用 LEFT JOIN 替代)
(3)CROSS JOIN
--startof 查询在职人数
sql语句
--end of
BEGIN TRAN
UPDATE a SET 字段=''
ROLLBACK
BEGIN TRANSACTION
--事务回滚开始
--检查报错
IF ( @@ERROR > 0 )
BEGIN
--回滚操作
ROLLBACK TRANSACTION
RAISERROR('删除工作报告错误', 16, 3)
RETURN
END
--结束事务
COMMIT TRANSACTION
公众号内回复1,拉你进微信交流群
长按下方二维码,和大家一起练SQL
点击"阅读原文",了解SQL训练营