天涯论坛

 找回密码
 立即注册
搜索
查看: 61|回复: 2

52条SQL语句性能优化策略,意见保藏

[复制链接]

3088

主题

2万

回帖

9909万

积分

论坛元老

Rank: 8Rank: 8

积分
99098774
发表于 2024-8-4 15:54:25 | 显示全部楼层 |阅读模式

阅读本文大概必须 12.5 分钟。

来自:cnblogs.com/SimpleWu/p/9929043.html

本文会说到 52 条 SQL 语句性能优化策略。1、对查找进行优化,应尽可能避免全表扫描,首要思虑在 WHERE 及 ORDER BY 触及的列上创立索引。2、应尽可能避免在 WHERE 子句中对字段进行 NULL 值判断,创建表时 NULL 是默认值,但大都数时候应该运用 NOT NULL,运用一个特殊的值,如 0,-1 做为默认值。3、应尽可能避免在 WHERE 子句中运用 != 或 <> 操作符。MySQL 仅有对以下操作符才运用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些时候的 LIKE。4、应尽可能避免在 WHERE 子句中运用 OR 来连接要求,否则将引起引擎放弃运用索引而进行全表扫描,能够运用 UNION 合并查找select id from t where num=10 union all select id from t where num=205、IN 和 NOT IN 要慎用,否则会引起全表扫描。针对连续的数值,能用 BETWEEN 就不要用 IN:select id from t where num between 1 and 36、下面的查找引起全表扫描:select id from t where name like‘%abc%’select id from t where name like‘%abc’若要提有效率,能够思虑全文检索。而select id from t where name like‘abc%’才用到索引。7、倘若在 WHERE 子句中运用参数,引起全表扫描。8、应尽可能避免在 WHERE 子句中对字段进行表达式操作,应尽可能避免在 WHERE 子句中对字段进行函数操作。9、非常多时候用 EXISTS 代替 IN 是一个好的选取select num from a where num in(select num from b)。用下面的语句替换:select num from a where exists(select 1 from b where num=a.num)十、索引固然能够加强相应的 SELECT 的效率,但同期降低了 INSERT 及 UPDATE 的效。由于 INSERT 或 UPDATE 时有可能会重建索引,因此怎么样建索引必须谨慎思虑,视详细状况而定。一个表的索引数最好不要超过 6 个,若太多则应思虑有些不常运用到的列上建的索引是不是有必要。11、应尽可能的避免更新 clustered 索引数据列, 由于 clustered 索引数据列的次序便是表记录的理学存储次序,一旦该列值改变将引起全部表记录的次序调节,会耗费相当大的资源。若应用系统必须频繁更新 clustered 索引数据列,那样必须思虑是不是应将该索引建为 clustered 索引。12、尽可能运用数字型字段,若只含数值信息的字段尽可能不要设计为字符型,这会降低查找和连接的性能,并会增多存储开销。13、尽可能的运用 varchar, nvarchar 代替 char, nchar。由于首要变长字段存储空间小,能够节省存储空间,其次针对查找来讲,在一个相对较小的字段内搜索效率显然要高些。14、最好不要运用返回所有:select from t ,用详细的字段列表代替 “*”,不要返回用不到的任何字段。15、尽可能避免向客户端返回大数据量,若数据量过大,应该思虑相应需求是不是恰当16、运用表的别名(Alias):当在 SQL 语句中连接多个表时,请运用表的别名并把别名前缀于每一个 Column 上。这般一来,就能够减少解析的时间并减少哪些由 Column 歧义导致的语法错误。17、运用“临时表”暂存中间结果 :简化 SQL 语句的重要办法便是采用临时表暂存中间结果。然则临时表的好处远远不止这些,将临时结果暂存在临时表,后面的查找就在 tempdb 中了,这能够避免程序中多次扫描主表,大大减少了程序执行中“共享锁”阻塞“更新锁”,减少了阻塞,加强了并发性能。18、有些 SQL 查找语句应加上 nolock,读、写是会相互阻塞的,为了加强并发性能。针对有些查找能够加上 nolock,这般读的时候能够准许写,但缺点是可能读到未提交的脏数据。运用 nolock 有3条原则:

查找的结果用于“插、删、改”的不可加 nolock;

查找的表属于频繁出现页分裂的,慎用 nolock ;

运用临时表同样能够保留“数据前影”,起到类似 Oracle 的 undo 表空间的功能,能采用临时表加强并发性能的,不要用 nolock。

19、平常的简化规则如下:不要有超过 5 个以上的表连接(JOIN),思虑运用临时表或表变量存放中间结果。少用子查找,视图嵌套不要过深,通常视图嵌套不要超过 2 个为宜。20、将必须查找的结果预先计算好放在表中,查找的时候再Select。这在SQL7.0以前是最重要的手段,例如医院的住院费计算。21、用 OR 的字句能够分解成多个查找,并且经过 UNION 连接多个查找她们的速度只同是不是运用索引相关倘若查找必须用到联合索引,用 UNION all 执行的效率更高。多个 OR 的字句用到索引,改写成 UNION 的形式再试图与索引匹配。一个关键的问题是不是用到索引。22、在IN后面值的列表中,将显现最频繁的值放在最前面,显现得最少的放在最后面,减少判断的次数。23、尽可能将数据的处理工作放在服务器上,减少网络的开销,如运用存储过程。存储过程是编译好、优化过、并且被组织到一个执行规划里、且存储在数据库中的 SQL 语句,是掌控流语言的集合,速度当然快。反复执行的动态 SQL,能够运用临时存储过程,该过程(临时表)被放在 Tempdb 中。24、当服务器的内存够多时,配制线程数量 = 最大连接数+5这般能发挥最大的效率;否则运用配制线程数量< 最大连接数,启用 SQL SERVER 的线程池来处理倘若还是数量 = 最大连接数+5,严重的损害服务器的性能。

25、查找相关同写的次序

select a.personMemberID, * from chineseresume a,personmember b where personMemberID = b.referenceid and a.personMemberID = JCNPRH39681(A = B, B =号码select a.personMemberID, * from chineseresume a,personmember b where a.personMemberID = b.referenceid and a.personMemberID = JCNPRH39681 andb.referenceid =JCNPRH39681 (A = B, B = 号码, A = 号码select a.personMemberID, * from chineseresume a,personmember b where b.referenceid = JCNPRH39681 and a.personMemberID = JCNPRH39681 (B = 号码, A = 号码26、尽可能运用 EXISTS 代替 select count(1) 来判断是不是存在记录。count 函数仅有在统计表中所有行数时运用况且 count(1) 比 count(*) 更有效率。27、尽可能运用 “>=”,不要运用 “>”。28、索引的运用规范:

索引的创建要与应用结合思虑意见大的 OLTP 表不要超过 6 个索引;

尽可能的运用索引字段做为查找要求,尤其是聚簇索引,必要时能够经过 index index_name 来强制指定索引;

避免对大表查找时进行 table scan,必要时思虑新建索引;

运用索引字段做为要求时,倘若该索引是联合索引,那样必要运用到该索引中的第1个字段做为要求才可保准系统运用该索引,否则该索引将不会被运用

重视索引的守护,周期性重建索引,重新编译存储过程。  

29、下列 SQL 要求语句中的列都建有恰当的索引,但执行速度却非常慢:

SELECT * FROM record WHERE substrINg(card_no, 1, 4) = 5378 --13秒 SELECT * FROM record WHERE amount/30 < 1000 --11秒 SELECT * FROM record WHERE convert(char(10), date, 112) = 19991201 --10秒分析: WHERE 子句中对列的任何操作结果都是在 SQL 运行时逐列计算得到的,因此呢它不得不进行表搜索,而运用该列上面的索引。

倘若这些结果在查找编译时就能得到,那样能够被 SQL 优化器优化,运用索引,避免表搜索,因此呢将 SQL 重写成下面这般

SELECT * FROM record WHERE card_no like 5378% -- < 1秒 SELECT * FROM record WHERE amount < 1000*30 -- < 1秒 SELECT * FROM record WHERE date = 1999/12/01 -- < 1秒30、当有一批处理的插进或更新时,用批量插进或批量更新,绝不会一条条记录的去更新。

31、在所有的存储过程中,能够用 SQL 语句的,我绝不会用循环去实现。

例如:列出上个月的每一天,我会用 connect by 去递归查找一下,绝不会去用循环从上个月第1天到最后一天。32、选取最有效率的表名次序仅在基于规则的优化器中有效): Oracle 的解析器根据从右到左的次序处理 FROM 子句中的表名,FROM 子句中写在最后的表(基本表 driving table)将被最先处理,在 FROM 子句中包括多个表的状况下,你必要选取记录条数最少的表做为基本表。倘若有 3 个以上的表连接查找,那就必须选取交叉表(intersection table)做为基本表,交叉表指的是那个被其他表所引用的表。33、加强 GROUP BY 语句的效率,能够经过将不必须的记录在 GROUP BY 之前过滤掉。下面两个查找返回相同结果,但第二个显著就快了许多。低效:SELECT JOB, AVG(SAL) FROM EMP GROUP BY JOB HAVING JOB = PRESIDENT OR JOB = MANAGER 有效SELECT JOB, AVG(SAL) FROM EMPWHERE JOB = PRESIDENT OR JOB = MANAGER GROUP BY JOB34、SQL 语句用大写,由于 Oracle 总是先解析 SQL 语句,把小写的字母转换成大写的再执行。35、别名的运用,别名是大型数据库的应用技巧,便是表名、列名在查找中以一个字母为别名,查找速度要比建连接表快 1.5 倍。36、避免死锁,在你的存储过程和触发器中拜访同一个表时总是以相同的次序;事务应经可能地缩短,在一个事务中应尽可能减少触及到的数据量;永远不要在事务中等待用户输入。37、避免运用临时表,除非却有必须,否则应尽可能避免运用临时表,相反,能够运用表变量代替。大都数时候(99%),表变量驻扎在内存中,因此呢速度比临时表更快,临时表驻扎在 TempDb 数据库中,因此呢临时表上的操作必须跨数据库通信,速度自然慢。38、最好不要运用触发器:

触发一个触发器,执行一个触发器事件本身便是一个耗费资源的过程;

倘若能够运用约束实现的,尽可能不要运用触发器;

不要为区别的触发事件(Insert、Update 和 Delete)运用相同的触发器;

不要在触发器中运用事务型代码。

39、索引创建规则: 

表的主键、外键必要有索引; 

数据量超过 300 的表应该有索引; 

经常与其他表进行连接的表,在连接字段上应该创立索引; 

经常出此刻 WHERE 子句中的字段,尤其是大表的字段,应该创立索引; 

索引应该建在选取性高的字段上; 

索引应该建在小字段上,针对大的文本字段乃至超长字段,不要建索引;

复合索引的创立必须进行仔细分析,尽可能思虑用单字段索引代替; 

正确选取复合索引中的主列字段,通常选取性较好的字段; 

复合索引的几个字段是不是经常同期以 AND 方式出此刻 WHERE 子句中?单字段查找是不是极少乃至倘若是,则能够创立复合索引;否则思虑单字段索引; 

如果复合索引中包括的字段经常单独出此刻 WHERE 子句中,则分解为多个单字段索引;

倘若复合索引所包括的字段超过 3 个,那样仔细思虑其必要性,思虑减少复合的字段; 

倘若既有单字段索引,又有这几个字段上的复合索引,通常能够删除复合索引; 

频繁进行数据操作的表,不要创立太多的索引; 

删除无用的索引,避免对执行计划导致消极影响;

表上创立每一个索引都会增多存储开销,索引针对插进、删除、更新操作增多处理上的开销。另一太多的复合索引,在有单字段索引的状况下,通常都是存在价值的;相反,还会降低数据增多删除时的性能,尤其是对频繁更新的表来讲消极影响更大。 

尽可能不要对数据库中某个含有海量重复的值的字段创立索引。

40、MySQL 查找优化总结:运用查找日志去发掘查找运用执行计划去判断查找是不是正常运行,总是去测试你的查找瞧瞧是不是她们运行在最佳状态下。久而久之性能总会变化,避免在全部表上运用 count(*),它可能锁住整张表,使查找保持一致以便后续类似查找能够运用查找缓存,在适当的情形下运用 GROUP BY 而不是 DISTINCT,在 WHERE、GROUP BY 和 ORDER BY 子句中运用有索引的列,保持索引简单,不在多个索引中包括同一个列。有时候 MySQL 会运用错误的索引,针对这种状况运用 USE INDEX,检测运用 SQL_MODE=STRICT 的问题,针对记录数少于5的索引字段,在 UNION 的时候运用LIMIT不是是用OR。为了避免在更新前 SELECT,运用 INSERT ON DUPLICATE KEY INSERT IGNORE;不要用 UPDATE 去实现,不要运用 MAX;运用索引字段和 ORDER BY子句 LIMIT M,N 实质能够减缓查找在某些状况下,有节制地运用,在 WHERE 子句中运用 UNION 代替子查找,在重新起步的 MySQL,记得来温暖你的数据库,以保证数据在内存和查找速度快,思虑持久连接,而不是多个连接,以减少开销。基准查找包含运用服务器上的负载,有时一个简单的查找能够影响其他查找,当负载增多在服务器上,运用 SHOW PROCESSLIST 查看慢的和有问题的查找,在研发环境中产生的镜像数据中测试的所有可疑的查找41、MySQL 备份过程:

从二级复制服务器上进行备份;

在进行备份时期停止复制,以避免在数据依赖和外键约束上显现不一致;

彻底停止 MySQL,从数据库文件进行备份;

倘若运用 MySQL dump 进行备份,请同期备份二进制日志文件 – 保证复制中断;

不要信任 LVM 快照,这很可能产生数据不一致,将来会给你带来麻烦;

为了更易进行单表恢复,以表为单位导出数据——倘若数据是与其他表隔离的。 

运用 mysqldump 时请运用 –opt;

在备份之前检测和优化表;

为了更快的进行导入,在导入时临时禁用外键约束。;

为了更快的进行导入,在导入时临时禁用独一性检测;

在每一次备份后计算数据库,表以及索引的尺寸,以便更够监控数据尺寸的增长;

经过自动调度脚本监控复制实例的错误和延迟;

定时执行备份。

42、查找缓冲并不自动处理空格,因此呢,在写 SQL 语句时,应尽可能减少空格的运用,尤其是在 SQL 首和尾的空格(由于查找缓冲并不自动截取首尾空格)。43、member 用 mid 做标准进行分表方便查找么?通常的业务需求中基本上都是以 username 为查找依据,正常应当是 username 做 hash 取模来分表。而分表的话 MySQL 的 partition 功能便是干这个的,对代码是透明的;在代码层面去实现貌似是不恰当的。44、咱们应该为数据库里的每张表都设置一个 ID 做为其主键,况且最好的是一个 INT 型的(举荐运用 UNSIGNED),并设置上自动增多的 AUTO_INCREMENT 标志。45、在所有的存储过程和触发器的起始处设置 SET NOCOUNT ON,在结束时设置 SET NOCOUNT OFF。无需在执行存储过程和触发器的每一个语句后向客户端发送 DONE_IN_PROC 信息46、MySQL 查找能够启用高速查找缓存。这是加强数据库性能的有效MySQL优化办法之一。当同一个查找被执行多次时,从缓存中提取数据和直接从数据库中返回数据快非常多47、EXPLAIN SELECT 查找用来跟踪查看效果:运用 EXPLAIN 关键字能够让你晓得 MySQL 是怎样处理你的 SQL 语句的。这能够帮你分析你的查找语句或是表结构的性能瓶颈。EXPLAIN 的查找结果还会告诉你你的索引主键被怎样利用的,你的数据表是怎样被搜索和排序的。48、当只要一行数据时运用 LIMIT 1 :当你查找表的有些时候,你已然晓得结果只会有一条结果,但由于你可能必须去fetch游标,或是你许会去检测返回的记录数。在这种状况下,加上 LIMIT 1 能够增多性能。这般一来,MySQL 数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据。49、选择表合适存储引擎:

myisam:应用时以读和插进做为主,仅有少量的更新和删除,并且对事务的完整性,并发性需求不是很高的。 

InnoDB:事务处理,以及并发要求需求数据的一致性。除了插进查找外,包含非常多的更新和删除。(InnoDB 有效地降低删除和更新引起的锁定)。

针对支持事务的 InnoDB类 型的表来讲,影响速度的重点原由是 AUTOCOMMIT 默认设置是打开的,况且程序显式调用 BEGIN 起始事务,引起插进一条都自动提交,严重影响了速度。能够在执行 SQL 前调用 begin,多条 SQL 形成一个事物(即使 autocommit 打开能够),将大大加强性能。

50、优化表的数据类型,选取合适的数据类型:原则:更小一般更好,简单就好,所有字段都得有默认值,尽可能避免 NULL。 例如:数据库表设计时候更小的占磁盘空间尽可能运用更小的整数类型。(mediumint 就比 int 更合适) 例如时间字段:datetime 和 timestamp。datetime 占用8个字节,timestamp 占用4个字节,只用了一半。而 timestamp 暗示的范围是 1970—2037 适合做更新时间。MySQL能够很好的支持大数据量的存取,然则通常说来,数据库中的表越小,在它上面执行的查找就会越快。 因此呢,在创建表的时候,为了得到更好的性能,咱们能够将表中字段的宽度设得尽可能小。例如:在定义邮政编码这个字段时,倘若将其设置为 CHAR(255),显然给数据库增多了不必要的空间。乃至运用VARCHAR 这种类型是多余的,由于 CHAR(6) 就能够很好的完成任务了。一样的,倘若能够的话,咱们应该运用 MEDIUMINT 而不是 BIGIN 来定义整型字段,应该尽可能把字段设置为 NOT NULL,这般在将来执行查找的时候,数据库不消去比较 NULL 值。针对某些文本字段,例如“省份”“性别”,咱们能够将它们定义为 ENUM 类型。由于在 MySQL 中,ENUM 类型被当作数值型数据来处理,而数值型数据被处理起来的速度要比文本类型快得多。这般咱们能够加强数据库的性能。51、字符串数据类型:char, varchar, text 选取区别。52、任何对列的操作都将引起表扫描,它包含数据库函数、计算表达式等等,查找时要尽可能将操作移至等号右边。<END>

举荐阅读:

完全整理 | 365篇高质技术文案目录整理

算法之美 : 栈和队列

主宰这个世界的10大算法

彻底理解cookie、session、token

浅谈什么是递归算法

专注服务器后台技术栈知识总结分享

欢迎关注交流一起进步





上一篇:30条书写高质量SQL的意见,太有用了!
下一篇:为么 SQL 语句不要太多的 join?
回复

使用道具 举报

0

主题

392

回帖

1

积分

新手上路

Rank: 1

积分
1
发表于 2024-8-27 14:39:51 | 显示全部楼层
对于这个问题,我有不同的看法...
回复

使用道具 举报

0

主题

1万

回帖

1

积分

新手上路

Rank: 1

积分
1
发表于 2024-9-1 07:50:15 | 显示全部楼层
期待与你深入交流,共探知识的无穷魅力。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站点统计|Archiver|手机版|小黑屋|天涯论坛 ( 非经营性网站 )|网站地图

GMT+8, 2024-11-22 17:57 , Processed in 0.239424 second(s), 21 queries .

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.