乐趣区

关于java:爆肝52条SQL语句性能优化干货必收藏

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=20

5,in 和 not in 也要慎用,否则会导致全表扫描,对于间断的数值,能用 between 就不要用 in 了:Select id from t where num between 1 and 3

6,上面的查问也将导致全表扫描: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)

10, 索引诚然能够进步相应的 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’and b.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,必要时思考新建索引;在应用索引字段作为条件时,如果该索引是联结索引,那么必须应用到该索引中的第一个字段作为条件时能力保证系统应用该索引,否则该索引将不会被应用;要留神索引的保护,周期性重建索引,从新编译存储过程。

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< 100030(< 1 秒)

SELECT * FROM record WHERE date=‘1999/12/01’(< 1 秒)

30,当有一批解决的插入或更新时,用批量插入或批量更新,绝不会一条条记录的去更新!

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

(例如:列出上个月的每一天,我会用 connect by 去递归查问一下,绝不会去用循环从上个月第一天到最初一天)

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 EMP

WHERE JOB =’PRESIDENT’

OR JOB =’MANAGER’

GROUP BY JOB

34,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,任何对列的操作都将导致表扫描,它包含数据库函数、计算表达式等等,查问时要尽可能将操作移至等号左边。

作者 | SimpleWu
起源 | cnblogs.com/SimpleWu/p/9929043.html

退出移动版