数据库SQL调优的几种方式汇总

目录
  • char  vs varchar
  • 开启慢查询日志来定位查询慢的语句
  • 合理使用关键字
  • 优化查询缓存
  • 适当使用索引
  • 分割数据表
  • 非规范化的方式
  • 总结

最近在复习SQL调优,总结了下主要有以下几种方式:

char  vs varchar

1、如果文本字段始终是固定长度的(例如,US 邮编,其始终具有“XXXXX-XXXX”形式的规范表示),那么推荐使用char。varchar 类型的长度是可变的,而 char 类型是一个定长的字段,以 char(10) 为例,不管真实的存储内容多大或者是占了多少空间,都会消耗掉 10 个字符的空间,通俗来讲,当定义为 char(10) 时,即使插入的内容是 'abc' 3 个字符,它依然会占用 10 个字节,其中包含了 7 个空字节。

2、CHAR 在快速、随机访问时效率很高。使用 VARCHAR,如果你想读取下一个字符串,不得不先读取到当前字符串的末尾,查找效率比较低。

3、char 长度最大为 255 个字符,varchar 长度最大为 65535 个字符

为什么varchar(255)而不是varchar(258),varchar(257)呢?

使用255是因为它是8位数字可以计算的最大字符数。它最大限度地利用了8位计数,而不需要另一个整字节来计算255以上的字符。

开启慢查询日志来定位查询慢的语句

启动慢查询日志,看哪些语句慢。默认是禁用慢查询日志的,--slow_query_log[={0|1}] 不指定或者为1,将启用日志。如果参数为0,此选项将禁用日志。--slow_query_log_file=file_name 来改变慢查询日志名称。

先找到慢查询的原因:

1、打开数据库慢查询日志,定义超时时间,比如超过2S就是慢查询

2、定位执行效率低的慢查询

show processlist

3、也可以通过explain来分析执行计划,explain得到的信息要主要关注:type字段,

possible_keys字段,key字段,key_len字段,rows,extra字段等

一般情况下慢查询的原因有以下这些:

没用索引或者索引失效

用了索引但是走了全表扫描

慢查询如何优化

索引+sql语句+架构优化+数据库结构优化

索引:避免索引失效

sql语句:优化insert语句:多条插入写一条,数据有序的插入;分页优化:通过子查询优化,比如查询2w起后面10条数据,先通过子查询拿到20000的id,然后通过主键索引,通过B+树定位到拿到的id对应的行数据,然后再向后取10条数据;

架构优化:数据库读写分离,主库写,从库读;

数据库结构优化:将字段比较多的表分解成多个表,将字段使用频率高的和字段使用频率低的分开,对于一些要进行联合查询的表,可以考虑建立中间表

合理使用关键字

比如MySQL还有其他更危险的关键字,应该谨慎使用。其中包括INSERT DELAYED,它告诉MySQL立即插入数据并不重要(例如,在日志记录情况下)。问题是,在高负载情况下,插入可能会无限期延迟,导致插入队列停滞。

优化查询缓存

查询缓存相关的服务器变量:

query_cache_min_res_unit:查询缓存中内存块的最小分配单位,默认4k,较小值会减少浪费,但会导致更频繁的内存分配操作,较大值会带来浪费,会导致碎片过多,内存不足
query_cache_limit:单个查询结果能缓存的最大值,单位字节,默认为1M,对于查询结果过大而无法缓存的语句,建议使用SQL_NO_CACHE
query_cache_size:查询缓存总共可用的内存空间;单位字节,必须是1024的整数倍,最小值40KB,低于此值有警报
query_cache_wlock_invalidate:如果某表被其它的会话锁定,是否仍然可以从查询缓存中返回结果,默认值为OFF,表示可以在表被其它会话锁定的场景中继续从缓存返回数据;ON则表示不允许
query_cache_type:是否开启缓存功能,取值为ON, OFF, DEMAND

查询缓存相关的状态变量:
show gloable status like 'Qcache%' ;

innodb_buffer_pool_size:这是任何使用innodb的安装都要考虑的#1设置。缓冲池是缓存数据和索引的地方:使其尽可能大将确保大多数读取操作使用内存而不是磁盘。典型值为5-6GB(8GB RAM)、20-25GB(32GB RAM)、100-120GB(128GB RAM)。
innodb_log_file_size:这是重做日志的大小。重做日志用于确保写入速度和持久性,以及在崩溃恢复期间。在MySQL 5.1之前,很难进行调整,因为您既需要大的重做日志来获得良好的性能,也需要小的重做日志来实现快速的崩溃恢复。幸运的是,自MySQL 5.5以来,崩溃恢复性能有了很大提高,因此您现在可以拥有良好的写性能和快速的崩溃恢复。在MySQL 5.5之前,重做日志的总大小限制为4GB(默认为有2个日志文件)。这在MySQL 5.6中得到了提升。

max_connections:如果经常遇到“连接数过多”错误,则最大连接数太低。由于应用程序无法正确关闭与数据库的连接,因此经常需要比默认的151个连接多得多的连接。

查询缓存的优化路线

在早期版本mysql均支持缓存,但是随着redis等内存型高性能的缓存技术兴起,mysql已经抛弃自己的缓存功能,mysql8.0以后不再支持缓存功能。

适当使用索引

每个索引都需要与表中的行数成比例的空间,因此太多的索引最终会占用更多内存。由于每次写入都需要更新相应的索引,因此写入操作的性能也会受到影响。通过分析代码,可以发现一个平衡点。这因系统和实施而异。

  • 查询(SELECT、GROUP BY、ORDER BY、JOIN)的列如果用了索引会更快
  • 索引通常表示为自平衡的 B 树,可以保持数据有序,并允许在对数时间内进行搜索,顺序访问,插入,删除操作
  • 设置索引,会将数据存在内存中,占用了更多内存空间
  • 写入操作会变慢,因为索引需要被更新
  • 加载大量数据时,禁用索引再加载数据,然后重建索引,这样也许会更快

索引何时会失效?

索引 (Index) 是帮助 MySQL 高效获取数据的数据结构。我们可以简单理解为:快速查找排好序的一种数据结构。

当索引不起作用时,会引起全表查询,索引就会失效,引起慢查询,有以下几种情况:

  • 模糊查询,比如以%开头的like查询。
  • 在索引列上操作or, not in , !=,<>,等操作
  • 如果查询条件有or,并且or的前后条件中有一个列没有索引,则涉及的索引都不会用到

1、避免索引失效,减少%like这种索引失效语句

2、合理创建索引

3、分页查询优化,可以通过子查询,关联查询优化,比如要查询从10000行开始的10行数据,看似只返回了10条数据,但是数据库引擎需要查询10010数据,然后将前面的10000条数据丢弃,性能可想而知,针对这种情况,我们可以先定位到上次分页的id,然后对id做条件索引查询;或者将原有的sql拆成2步,首先查询出一页数据中的最小id,然后通过索引树,定位到最小id索引树节点位置,通过偏移量来读取后面的10条数据

4、避免使用select *

select *的查询过程:先在字段的二级索引B+树上,查出对应的主键id列表

然后进行回表操作,在主键索引中 查询id对应的行数据

5.通过explain来分析SQL执行计划,看是否用到了索引

explain得到的字段key(使用到的索引),rows(MYSQL估计为了查找目标行而需要读取的行数:),possible_keys(查询可能会使用的索引)等主要关注type

Type:以怎样的方式查找表中的行的方式(性能逐渐变好)

All:   全表扫描

Index:  根据索引的次序进行全表扫描,若在extra出现using index表示使用覆盖索引,而非全表扫描

Range:  根据索引实现的范围扫描

Ref:  根据索引返回表中匹配某单个值的所有行

Eq_ref:  仅返回一个行,但需要和某个参考值作比较

Const,system:  根据具有唯一性的索引(比如主键)查找时,返回的是一行

NULL:类似于覆盖查询

Id:当前查询中,每个Select语句的编号

复杂类型的查询三种:

  • 简单子查询:
  • 用于from中的子查询
  • 联合查询,union

注意:union查询的分析结果中会出现一个额外的匿名临时表

Select_type:

简单查询为simple

复杂查询:

Subquery:简单子查询

Derived:用于from中的子查询

Union:用于union第一个之后的select语句

possible_keys:  查询可能会使用的索引

Key:  使用到的索引

Key_len:  索引中使用的字节数,比如索引有70个字节数,只是用了20个

ref:  在利用key所表示的索引完成查询时,所用的列或某常量值

rows:  MYSQL估计为了查找目标行而需要读取的行数:

Extra:额外信息

Using index:会使用覆盖索引,以避免访问表

Using where:服务器将在存储引擎检索后,再进行一次过滤

Using temporary:对结果排序时会使用临时表

Using filesort:对结果使用一个外部索引排序

例如:

MariaDB [testdb]> explain select sname,age from stu union select tname,age from teacher\G;

*************************** 1. row ***************************

           id: 1
  select_type: PRIMARY
        table: stu
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 7
        Extra:

*************************** 2. row ***************************

           id: 2
  select_type: UNION
        table: teacher
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 3
        Extra:

*************************** 3. row ***************************

           id: NULL   联合前两个表   匿名临时表
  select_type: UNION RESULT
        table: <union1,2>
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra:
3 rows in set (0.00 sec)
ERROR: No query specified

分割数据表

将热点数据拆分到单独的数据表中,可以有助于缓存

例如,在博客上,可能会在许多地方显示条目标题(例如,最近发布的文章列表). 经常访问的数据保存在一个表中,而不经常访问的数据保存在另一个表中。由于数据现在已分区,因此不经常访问的数据占用的内存更少。

非规范化的方式

非规范化: 非规范化是一种用于先前规范化数据库以提高性能的策略。在计算中,非规范化是指通过添加数据的冗余副本或对数据进行分组,以牺牲某些写入性能为代价,尝试提高数据库的读取性能的过程

这通常是由需要执行大量读取操作的关系数据库软件的性能或可扩展性引起的。一般情况下,只需要在性能需要的地方进行非规范化。

参考:

总结

到此这篇关于数据库SQL调优的几种方式的文章就介绍到这了,更多相关SQL调优方式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • mysql sql语句性能调优简单实例

     mysql sql语句性能调优简单实例 在做服务器开发时,有时候对并发量有一定的要求,有时候影响速度的是某个sql语句,比如某个存储过程.现在假设服务器代码执行过程中,某个sql执行比较缓慢,那如何进行优化呢? 假如现在服务器代码执行如下sql存储过程特别缓慢: call sp_wplogin_register(1, 1, 1, '830000', '222222'); 可以按如下方法来进行调试: 1. 打开mysql profiling: 2. 然后执行需要调优的sql,我们这里执行两条sq

  • 千万级用户系统SQL调优实战分享

    用户日活百万级,注册用户千万级,而且若还没有进行分库分表,则该DB里的用户表可能就一张,单表上千万的用户数据. 某系统专门通过各种条件筛选大量用户,接着对那些用户去推送一些消息: 一些促销活动消息 让你办会员卡的消息 告诉你有一个特价商品的消息 通过一些条件筛选出大量用户,针对这些用户做推送,该过程较耗时-筛选用户过程. 用户日活百万级,注册用户千万级,而且若还没有进行分库分表,则该DB里的用户表可能就一张,单表上千万的用户数据. 对运营系统筛选用户的SQL: SELECT id, name 

  • 一次SQL调优数据库性能问题后的过程(300W)

    将绝大部分的SQL查询改为存储过程,这样的操作毫无疑问可以提高部分性能. 凡是使用"select * from xxx"的操作一律具体到所需字段. 使用join连接2个以上大量数据的表,且基础数据表变化不大的查询一律使用视图,并为此视图建立索引.理由来自SQL Server联机帮助手册: "对于标准视图而言,为每个引用视图的查询动态生成结果集的开销很大,特别是对于那些涉及对大量行进行复杂处理(如聚合大量数据或联接许多行)的视图.如果在查询中频繁地引用这类视图,可通过对视图创建

  • 数据库SQL调优的几种方式汇总

    目录 char  vs varchar 开启慢查询日志来定位查询慢的语句 合理使用关键字 优化查询缓存 适当使用索引 分割数据表 非规范化的方式 总结 最近在复习SQL调优,总结了下主要有以下几种方式: char  vs varchar 1.如果文本字段始终是固定长度的(例如,US 邮编,其始终具有“XXXXX-XXXX”形式的规范表示),那么推荐使用char.varchar 类型的长度是可变的,而 char 类型是一个定长的字段,以 char(10) 为例,不管真实的存储内容多大或者是占了多少

  • MyBatis下SQL注入攻击的3种方式

    目录 前言 Mybatis框架下易产生SQL注入漏洞的情况主要分为以下三种: 1.模糊查询 2.in 之后的多个参数 3.order by 之后 二.实战思路 三.总结 前言 SQL注入漏洞作为WEB安全的最常见的漏洞之一,在java中随着预编译与各种ORM框架的使用,注入问题也越来越少.新手代码审计者往往对Java Web应用的多个框架组合而心生畏惧,不知如何下手,希望通过Mybatis框架使用不当导致的SQL注入问题为例,能够抛砖引玉给新手一些思路. Mybatis的SQL语句可以基于注解的

  • eclipse修改jvm参数调优方法(2种)

    本文介绍了eclipse修改jvm参数调优方法(2种),分享给大家,具体如下: 一般在不对eclipse进行相关设置的时候,使用eclipse总是会觉得启动好慢,用起来好卡,其实只要对eclipse的相关参数进行一些配置,就会有很大的改善. 有两种方法: 1.打开eclipse配置文件eclipse.ini,更改把-Xmx(其数值代表jvm可以使用的最大内存数) 2.  运行java程序时,选择run->run configuration->arguments,输入-Xms100M -Xmx8

  • jvm调优的几种场景(小结)

    目录 一.cpu占用过高 (1)用top命令查看cpu占用情况 (2)用top -Hp命令查看线程的情况 (3)把线程号转换为16进制 (4)用jstack工具查看线程栈情况 二.死锁 三.内存泄漏 四.总结 假定你已经了解了运行时的数据区域和常用的垃圾回收算法,也了解了Hotspot支持的垃圾回收器. 一.cpu占用过高 cpu占用过高要分情况讨论,是不是业务上在搞活动,突然有大批的流量进来,而且活动结束后cpu占用率就下降了,如果是这种情况其实可以不用太关心,因为请求越多,需要处理的线程数越

  • Python调用REST API接口的几种方式汇总

    相信做过自动化运维的同学都用过REST API接口来完成某些动作.API是一套成熟系统所必需的接口,可以被其他系统或脚本来调用,这也是自动化运维的必修课. 本文主要介绍python中调用REST API的几种方式,下面是python中会用到的库. - urllib2 - httplib2 - pycurl - requests urllib2 - Sample1 import urllib2, urllib github_url = 'https://api.github.com/user/re

  • Oracle 遍历游标的四种方式汇总(for、fetch、while、BULK COLLECT)

    1.情景展示 Oracle 遍历游标的四种方式(for.fetch.while.bulk collect+forall) 2.问题分析 我们可以把游标想象成一张表,想要遍历游标,就要取到游标的每行数据,所以问题的关键就成了:如何取到行数据? 3.解决方案 方式一:FOR 循环(推荐使用) 变形一:遍历显式游标 /* 如果是在存储过程外使用显式游标,需要使用DECLARE关键字 */ DECLARE   /*创建游标*/   CURSOR CUR_FIRST_INDEX IS     SELECT

  • 实现oracle数据库字段自增长(两种方式)

    程序猿都知道mysql等其他的数据库都有随着记录的插入而表ID会自动增长的功能,反而oracle却没有这一功能,下面通过两种方式来解决字段增长的功能,具体内容情况下文. 因为两种方式都需要通过创建序列来实现,这里先给出序列的创建方式. 复制代码 代码如下: CREATE SEQUENCE 序列名 [INCREMENT BY n] [START WITH n] [{MAXVALUE/ MINVALUE n|NOMAXVALUE}] [{CYCLE|NOCYCLE}] [{CACHE n|NOCAC

  • Java读取properties配置文件的8种方式汇总

    目录 一.前言 二.Properties类 三.Properties常用方法实践 四.Java写入Properties 五.Java读取Properties 六.Properties配合Spring框架使用 七.完整代码 总结 一.前言 在做Java项目开发过程中,涉及到一些数据库服务连接配置.缓存服务器连接配置等,通常情况下我们会将这些不太变动的配置信息存储在以 .properties 结尾的配置文件中.当对应的服务器地址或者账号密码信息有所变动时,我们只需要修改一下配置文件中的信息即可.同时

  • Java 实现多线程的几种方式汇总

    我们先来看段示例代码 import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class Main { public static void main(String[] args) { //方法一:继承Thread int i = 0; // for(; i < 100; i++){ // System.out.println(Thread.currentThread().getNa

随机推荐