本文是学习《高性能 Mysql》中关于 Mysql 中查询优化须要注意的一些要点的总结:mysql
-- 虽然 id 上创建了索引,可是没法使用索引优化
select id from user where id + 1 =5;
复制代码
下面是建立冗余索引的几个例子:算法
- 建立了索引(A,B)再建立索引(A),那后者即是冗余索引
- 将一根索引扩展为(A,ID),其中 ID 是主键,对于 InnoDB 来讲主键已经包含在二级索引中了,因此这也是冗余的
复制代码
- 能够查到使用最多或者使用最少的表和索引
- 能够查到从未使用过的索引,考虑删除之
- 能够查到线程的使用状况等等
复制代码
- 让单表查询的缓存效率更高
- 拆分后用 IN() 代替关联查询,可让 Mysql 按照 ID 顺序去查找
- 能够将数据分布到不一样的 Mysql 服务器上
复制代码
- 若是是统计结果集的大小,请使用 COUNT(*),使用 COUNT(cloumn) 有可能某个列存在 NULL 致使统计不许确,排除 NULL 计算也是要成本的
- 对于 MyIsam 存储引擎,若是不带任何 WHERE 条件的状况下, COUNT(*) 不须要计算,直接经过存储引擎特性得到
复制代码
-- 分页时对于偏移量特别大的状况下,查询全部列分页将很是耗时,可使用“延迟关联”的方式,其中一个查询中尽量的使用索引覆盖扫描方式 LIMIT 查询出主键 ID,而后再和原表作一次关联返回须要的列:
-- 优化前
select * from user order by id limit 1000, 5;
-- 优化后
select user.* from user join (select id from user order by id limit 1000, 5) new_user on new_user.id = user.id;
-- 若是在一个位置上预先计算出了边界,能够将 limit 查询转换为已知位置的查询进行优化
select * from user where id between 1000 and 1005 order by id
复制代码
若是对优化器的执行计划不满意可使用优化器的几个提示来控制最终的执行计划:sql
HIGH_PRIORITY 和 LOW_PRIORITY 对于使用表锁的存储引擎有效,HIGH_PRIORITY 会将当前查询插入到全部处于表锁等待的 SQL 队列前面,而 LOW_PRIORITY 会将当前查询放在全部等待表锁的 SQL 队列队尾,只要队列中还有须要访问同一张表的 SQL, 它就被处于等待状态。数据库
该提示对 INSERT 和 REPLACE 有效,使用该提示后会当即返回给客户端,而后将插入的行放入缓存区,等待表空闲时批量写入数据。缓存
该操做致使 LAST_INSERT_ID() 函数没法正常工做。安全
对于一些数据记录,即便插入失败也不影响服务正常运行,可使用该操做,及时响应客户端,加快响应速度。bash
让全部查询中的的表按照语句中出现的顺序进行关联,不须要 Mysql 优化器去从新选择关联顺序,若是能确保本身写的关联顺序性能比较好的状况下能够选择该提示,减小 Mysql 优化器自己选择分析的时间。服务器
这两个提示针对 select 操做,告诉优化器对 group by 或 distinct 如何使用临时表及排序,若是 SQL_SMALL_RESULT 表示结果集很小,使用内存排序,若是是 SQL_BIG_RESULT 表示结果集很大,使用磁盘临时表排序。网络
这个提示告诉 Mysql 结果集是否要缓存在查询缓存中数据结构
FOUND_ROWS 这个函数通常状况下只会返回上一次查询的数据集大小,可是若是加了 SQL_CALC_FOUND_ROWS 提示,那么将返回不带 limit 状况下整个数据集大小,这个参数对于分页有必定的用处,不须要屡次查询。
该提示只对支持行级锁的存储引擎生效,该提示会对查询中符合条件的数据加锁
这两个提示会让 InnoDB 覆盖索引优化失效,由于 InnoDB 须要访问主键中的版本信息。
告诉优化器是否使用某个索引
- 用多个小表代替一个大表,可让缓存失效在一个更细的粒度上进行
- 批量写入时只作一次缓存失效,因此比单条写入更好
- 若是没法在数据库或者表级别控制查询缓存,则可使用 SQL_CACHE 和 SQL_NO_CACHE 来控制单个 select 语句是否进行缓存,而且能够修改会话级别的 query_cache_type 来控制查询缓存
- 对于写密集型的应用来讲,关闭查询缓存对性能会更好
复制代码
datadir= /var/lib/mysql # 数据的存储位置
user= mysql # 执行 mysql 用户运行 mysql 实例,要保证该用户存在
port= 3306 # mysql 实例的端口号
socket: =/var/lib/mysql/mysql.sock # socket 文件存储位置,用于 TCP/IP 套接字链接数据库
pid_file = /var/lib/mysql/mysql.pid # mysql 进程 id
default_storage_engine = InnoDB # 默认的存储引擎
innodb = FORCE # 只有在 Innodb 存储引擎正常启动时,服务器才能正常启动,通常建议设置为 FORCE,保证能够正确使用 InnoDB 存储引擎
innodb_buffer_pool_size = <value> # InnoDB 存储引擎可使用的缓存大小
innodb_log_file_size = <value> # 设置重作日志大小,过小写入日志须要频繁的刷新磁盘,使写入变慢,太大奔溃恢复时间变慢,要合理设置
innodb_thread_concurrency = 0 # 它能够限制一次性有多少线程进入内核,0 表示不限制。通常建议设置为:CPU 数量 * 磁盘数量 * 2
innodb_thread_sleep_delay = 10000 # 为了减小由于操做系统调度引发的上下文切换,线程第一次没法进入内核会休眠 innodb_thread_sleep_delay 秒之后再尝试
# 若是再次没法进入内核,则放入线程等待队列,让操做系统来处理
innodb_file_per_table = 1 # 是否让每一张表使用一个独立文件存储,使得删除表变的简单,而且容易分散到不一样的磁盘上,可是会致使空间的浪费
innodb_flush_method = 0_DIRECT # 控制 InnoDB 如何和文件系统相互做用,控制将数据刷新到磁盘的方式,要不要使用磁盘缓存等
key_buffer_size = <value> # MyISAM 存储引擎分配的键缓存大小,该值对使用 MyISAM 存储引擎的数据库很是重要
# 即便是使用 InnoDB 存储引擎也应该分配必定空间(32M),由于 Mysql 中一些系统表会使用 MyISAM 存储引擎
# Group by 建立临时表时也可能使用 MyISAM 存储引擎
sort_buffer_size = <value> # 该参数会在查询使用内存排序时分配内存,一旦须要排序就会指定这么大的内存,无论是否须要这么大的内存
# 通常建议把 sort_buffer_size 修改的小一点,若是某个查询确实须要很大内存排序,能够在会话级临时调大该值
log_error=/var/lib/mysql/mysql-error.log # 错误日志存放位置
slow_query_log=/var/lib/mysql/mysql-show.log# 慢查询日志存放位置
tmp_table_size/max_heap_table_size = 32M # 这两个变量用于控制使用内存临时表(Memory存储引擎)的大小,若是超过这个值,将使用磁盘临时表(MyISAM存储引擎)
# 经过 show status 观察 Created_tmp_disk_tables 和 create_tmp_tables 的变化来调整这两个参数
query_cache_type = 0 # 控制查询缓存功能的开启和关闭,0 表示关闭,1 表示开启,2 表示只有 select 中明确指定 SQL_CACHE 才缓存
query_cache_size = 0 # 设置查询缓存的大小
max_connections = <value> # 最大链接数,默认是 100,每每过小,若是过小会报太多链接被拒绝的错误,观察 Max_used_connections 状态变量来设置该参数
thread_cache_size = <value> # 指定 Mysql 能够保存在缓存中的线程数,通常经过观察 Thread_connected 变量的大小来调整该值的大小
table_cache_size = 1000 # 设置表缓存大小,设置足够的大小以免老是须要从新打开并从新解析表定义
open_files_limit = 65535 # 这个参数能够尽可能设置大,由于打开句柄的开销很小,不然会出现“too many open files”
expire_logs_days = 10 # 服务器在指定的天数后清理二进制日志
max_connect_errors = 100 # 允许某个应用最大错误次数,若是超过该值,将被加入黑名单,除非刷新主机缓存
复制代码
- connect_timeout
在获取链接阶段(authenticate)起做用,获取 MySQL 链接是屡次握手的结果,除了用户名和密码的匹配校验外,还有 IP->HOST->DNS->IP 验证,任何一步均可能由于网络问题致使线程阻塞。
为了防止线程浪费在没必要要的校验等待上,超过 connect_timeout 的链接请求将会被拒绝,默认值 10 秒。
- interactive_timeout 和 wait_timeout
在链接空闲阶段(sleep)起做用,即便没有网络问题,也不能容许客户端一直占用链接。
对于保持 sleep 状态超过了 wait_timeout(或 interactive_timeout,取决于 client_interactive 标志)的客户端,MySQL 会主动断开链接,默认值是 8 小时。
- net_read_timeout 和 net_write_timeout
则是在链接繁忙阶段(query)起做用,即便链接没有处于 sleep 状态,即客户端忙于计算或者存储数据,MySQL 也选择了有条件的等待。
在数据包的分发过程当中,客户端可能来不及响应(发送、接收、或者处理数据包太慢)。
为了保证链接不被浪费在无尽的等待中,MySQL 也会选择有条件(net_read_timeout和net_write_timeout)地主动断开链接。默认是 30 秒。
- innodb_lock_wait_timeout
innodb 使用这个参数可以有效避免在资源有限的状况下产生太多的锁等待,指的是事务等待获取资源时等待的最长时间,超过这个时间还未分配到资源则会返回应用失败。
参数的时间单位是秒,最小可设置为1s(通常不会设置得这么小),最大可设置1073741824秒(34年),默认安装时这个值是 50 s。
超过这个时间会报 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction。
- innodb_rollback_on_timeout
默认状况下 innodb_lock_wait_timeout 超时后只是超时的 sql 执行失败,整个事务并不回滚,也不作提交。
如须要事务在超时的时候回滚,则须要设置 innodb_rollback_on_timeout=ON,该参数默认为 OFF。
- lock_wait_timeout
和 innodb_lock_wait_timeout 的区别是前者是 Innodb 的 DML 操做的行级锁的等待时间,后面是数据结构 DDL 操做的锁的等待时间。
- innodb_flush_log_at_timeout
参数 innodb_flush_log_at_trx_commit = 1 时,此超时参数不起做用。当 innodb_flush_log_at_trx_commit=0/2 时才起做用。
表示每 innodb_flush_log_at_timeout 秒进行一次的频率刷新 redo log(在 5.6.6 版本以前是固定每秒一次刷新 redo log,5.6.6 版本以后刷新频率能够经过这个参数设置,固然,这个参数自己默认值也是 1S)
复制代码