一、优化思想
- 硬件优化
- 软件优化
- my.cnf参数优化
- SQL语句优化
- 架构优化
1、硬件优化
硬件优化包括CPU、内存、硬盘、网卡的优化。一般的CPU可以使用2-4核,内存32G-64G,这样可以跑2个实例。
2、软件优化
操作系统使用x86_64系统。
3、my.cnf参数优化
[mysqld] user = root port = 3306 socket = /data/3306/mysql.socket basedir = /application/mysql datadir = data/3306/data # 数据目录 open_files_limit = 2000 #MySQ需要打开的文件描述符数量,默认为1024 back_log = 600 # back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。也就是说,如果MySql的连接数达到max_connections时,新来的请求将会被存在堆栈中,以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源。 max_connections = 2000 #MySQL最多连接数量 max_connect_errors = 20 #一个MySQL中与安全有关的计数器值,它负责阻止过多尝试失败的客户端以防止暴力破解密码的情况,默认为10,当尝试连接服务端10次失败后就会报错阻止,重置此值通过重启服务端或者客户端执行FLUSH HOSTS table_open_cache = 10 #用于设置table高速缓存的数量。当某一连接访问一个表时,MySQL会检查当前已缓存表的数量。如果该表已经在缓存中打开,则会直接访问缓存中的表已加快查询速度;如果该表未被缓存,则会将当前的表添加进缓存并进行查询。 max_allowed_packet = 20M #server接受的数据包大小,默认值为1048576(1M) sort_buffer_size = 1M #加速ORDER BY 或者GROUP BY 操作,它针对单个线程的,所以当多个线程同时进行排序的时候,系统中就会出现多个sort buffer join_buffer_size = 2M #增大join_buffer_size参数使全连接加快 thread_cache_size = 300 #MySQL服务缓存以重用的线程数,如果有客户端断开连接后再次连接到MySQL服务且线程在缓存中,则MySQL服务会优先使用缓存中的线程 thread_stack = 200KB #每个连接线程被创建时,MySQL给它分配的内存大小。当MySQL创建一个新的连接线程时,需要给它分配一定大小的内存堆栈空间,以便存放客户端的请求的Query及自身的各种状态和处理信息。 query_cache_size = 10M #为查询结果所分配的缓存,默认这个参数是没有开启 query_cache_size = 1M # 指定单个查询能够使用的缓冲区大小,默认值为1M query_cache_min_res_unit = 4M #查询缓存所分配的最小块的大小。默认值是4096(4KB) tmp_table_size = 200M #内部内存临时表的最大内存。这个参数不会应用到用户创建的MEMORY表。如果内存临时表的大小超过了这个参数的值,则MySQL会自动将超出的部分转化为磁盘上的临时表。 max_heap_table_size = 200M #定义了用户可以创建的内存表(memory table)的大小.这个值用来计算内存表的最大行数值 long_query_time = 2 #设置查询sql语句执行的时间 log-slow-queries = /data/3306/slow-log.log #记录超过long_query_time设置时间的sql查询语句 log-error = /data/3306/error.log #错误日志记录路径 pid-file = /data/3306/mysql.pid log-bin = /data/3306/mysql-bin #开启binlog relay-log = /data/3306/relay-bin #一般用于主从复制,从服务器的SQL线程读取relay-log应用到服务器与主服务器数据保持一致 relay-log-info-file = /data/3306/relay.log binlog_cache_size = 1M #为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存 expire_logs_days = 7 #设置日志过期时间为7天 key_buffer_size = 32M #指定索引缓冲区的大小,它决定索引处理的速度,尤其是索引读的速度 read_buffer_size = 1M #是MySQL读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。 read_rnd_buffer_size = 1M #这个参数用在MyISAM表和任何存储引擎表随机读所使用的内存。当从MyISAM表中以键排序读取数据的时候,扫描的行将使用这个缓存以避免磁盘的扫描。将这个值设到一个较大的值可以显著提升ORDER BY的性能。然后,这个参数会应用到所有的客户端连接,所有不应该将这个参数在全局级别设为一个较大的值;在运行大查询的会话中,在会话级别增大这个参数即可。 bulk_insert_buffer_size = 8M #批量插入数据 innodb_buffer_pool_size = 128M #InnoDB用来缓存它的数据和索引的内存缓冲区的大小。 innodb_data_file_path = ibdata1:1024M:autoextend #单独数据文件和它们尺寸的路径 innodb_file_io_threads = 4 #InnoDB中文件I/O线程的数量。正常地,这个参数是用默认的,默认值是4,但是大数值对Windows磁盘I/O有益 innodb_lock_wait_timeout = 120 #InnoDB事务在被回滚之前可以等待一个锁定的超时秒数 innodb_log_buffer_size = 8M #InnoDB用来往磁盘上的日志文件写操作的缓冲区的大小 innodb_log_file_size = 10M #在日志组里每个日志文件的大小。 [mysqldump] quick max_allowed_packet = 20M ...
4、SQL语句优化
(1)索引优化
- 通过my.cnf中配置(long_query_time、log-slow-queries)查出慢SQL语句进行优化
- 慢查询日志分析工具(mysqlsla、mysql-explain-slow-log等工具)定位分析
(2)拆分复杂SQL语句
- 子查询
- JOIN连表查询
- 表记录上千万
(3)禁止数据库中计算
数据库核心功能是用于存储数据而非计算,计算等逻辑在应用程序中去实现
(4)搜索功能
对于像... where like '%'之类的语句,不走索引,所以一般不要用MySQL可以使用es之类的专业搜索组件实现
5、架构优化
- 业务拆分(有的业务可以是用类似redis这种非关系型数据库实现)
- 数据库前端加缓存,比如memcached等
- 数据库集群与读写分离
- 表记录上千万,拆库拆表
二、优化实践
数据库出现问题,表现出的形式可能有很多种,比如网站访问速度很慢,那么应该如何去排查与解决呢?下面只是说明过程,并非真正实例:
1、查看负载
[root@hadoop-slave1 support-files]# uptime 11:33:07 up 20:57, 2 users, load average: 8.08, 9.03, 9.05
如果负载很高,说明有问题,此时应该查看是什么进程。
2、查看进程
[root@hadoop-slave1 support-files]# top top - 11:39:10 up 21:03, 2 users, load average: 0.00, 0.01, 0.05 Tasks: 220 total, 1 running, 219 sleeping, 0 stopped, 0 zombie %Cpu(s): 0.6 us, 0.8 sy, 0.0 ni, 98.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 999964 total, 74632 free, 720324 used, 205008 buff/cache KiB Swap: 2097148 total, 1950140 free, 147008 used. 107984 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 3080 root 20 0 3631320 151860 27536 S 6.0 15.2 2:58.06 gnome-shell 1291 root 20 0 357644 30528 11272 S 4.7 3.1 0:40.86 X
如果查看出MySQL进程cpu等占用太高,此时就应该去查看MySQL了。
3、查看MySQL线程
mysql> show full processlist; +----+------+-----------+------+---------+------+-------+------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+------+---------+------+-------+------------------------+ | 4 | root | localhost | NULL | Query | 0 | NULL | show full processlist | +----+------+-----------+------+---------+------+-------+------------------------+ 1 row in set (0.00 sec)
如果看到此处有大量线程等待,并且有执行的SQL语句,那么应该看看这条SQL语句是怎么回事。
4、SQL语句解析
主要查看是否利用了索引的情况:
mysql> explain select * from userinfo where username='张三'G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: userinfo type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 3 Extra: 1 row in set (0.00 sec)
像上面这种possible_keys、key、NULL、ref都是NULL显然是没有利用上任何索引。所以应该尝试添加索引进行优化。