一、索引创建和优化
索引的目的
- 快速访问数据表中的特定信息,提高检索速度
- 创建唯一性索引,保证数据库表中每一行数据的唯一性。
- 加速表和表之间的连接
- 使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间
引对数据库系统的负面影响
- 创建索引和维护索引需要耗费时间,这个时间随着数据量的增加而增加;
- 索引需要占用物理空间,不光是表需要占用数据空间,每个索引也需要占用物理空间;
- 当对表进行增、删、改、的时候索引也要动态维护,这样就降低了数据的维护速度。
数据表建立索引的原则
- 在最频繁使用的、用以缩小查询范围的字段上建立索引。
- 在频繁使用的、需要排序的字段上建立索引
什么情况下不宜建立索引
- 对于查询中很少涉及的列或者重复值比较多的列,不宜建立索引。
- 对于一些特殊的数据类型,不宜建立索引,比如文本字段(text)等
索引优化
- 只要列中含有NULL值,就最好不要在此例设置索引,复合索引如果有NULL值,此列在使用时也不会使用索引
- 尽量使用短索引,如果可以,应该制定一个前缀长度
- 对于经常在where子句使用的列,最好设置索引,这样会加快查找速度
- 对于有多个列where或者order by子句的,应该建立复合索引
- 对于like语句,以%或者‘-’开头的不会使用索引,以%结尾会使用索引
- 尽量不要在列上进行运算(函数操作和表达式操作)
- 尽量不要使用not in和<>操作
二、SQL慢查询
1. 如何捕获低效sql
- slow_query_log
这个参数设置为ON,可以捕获执行时间超过一定数值的SQL语句。
- ong_query_time
当SQL语句执行时间超过此数值时,就会被记录到日志中,建议设置为1或者更短。
- slow_query_log_file
记录日志的文件名。
- log_queries_not_using_indexes
这个参数设置为ON,可以捕获到所有未使用索引的SQL语句,尽管这个SQL语句有可能执行得挺快。
2. 慢查询优化的基本步骤
- 先运行看看是否真的很慢,注意设置SQL_NO_CACHE
- where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高
- explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
- order by limit 形式的sql语句让排序的表优先查
- 了解业务方使用场景
- 加索引时参照建索引的几大原则
3.优化原则
- 查询时,能不要就不用,尽量写全字段名
- 大部分情况连接效率远大于子查询
- 多使用explain和profile分析查询语句
- 查看慢查询日志,找出执行时间长的sql语句优化
- 多表连接时,尽量小表驱动大表,即小表 join 大表
- 在千万级分页时使用limit
- 对于经常使用的查询,可以开启缓存
4. 数据库表优化**
-
表的字段尽可能用NOT NULL
-
字段长度固定的表查询会更快
-
把数据库的大表按时间或一些标志分成小表。将表拆分
-
水平切分:将记录散列到不同的表中,各表的结构完全相同,每次从分表中查询, 提高效率。
-
垂直切分:将表中大字段单独拆分到另外一张表, 形成一对一的关系
-
三、读写分离,主从复制
主从复制
数据库主从复制(Database Master-Slave Replication)是一种用于提高数据库性能、可用性和冗余的技术。它允许将一个数据库服务器(主服务器)的数据复制到一个或多个其他数据库服务器(从服务器)上。这有助于分担读取负载、提供灾难恢复和数据备份,以及提高数据库的可用性。以下是数据库主从复制的基本原理:
1. 主服务器(Master)
- 主服务器是数据库系统的主要实例,它处理所有的写操作(INSERT、UPDATE、DELETE)以及一些读操作。
- 主服务器上的数据被称为“主数据库”。
- 主服务器负责将其数据的更改记录到二进制日志文件(Binary Log)中。
2. 从服务器(Slave)
- 从服务器是主服务器的副本,它接收主服务器上的数据更改并将其应用到自己的数据库中。
- 从服务器上的数据被称为“从数据库”。
- 从服务器不允许写入操作,它只处理读取操作。
3. 主从同步过程
- 主服务器将所有的写入操作记录到二进制日志中。
- 从服务器连接到主服务器并请求复制二进制日志。
- 主服务器将二进制日志的内容传输给从服务器。
- 从服务器将接收到的二进制日志内容逐一应用到自己的数据库,从而保持与主数据库的同步。
4. 延迟
- 从服务器上的数据复制通常会有一定的延迟,因为数据的传输和应用需要时间。
- 这意味着从服务器上的数据不会实时反映主服务器上的数据更改,但通常是可控制的。
5. 冲突处理
- 如果在主服务器和从服务器上同时对相同数据进行修改,可能会出现冲突。
- 通常,主从复制技术不负责解决冲突,而是要求开发者在应用层面处理这些问题。
主从复制的应用场景包括:
- 提供读取负载均衡:从服务器可以分担主服务器的读取请求,从而减轻主服务器的负担。
- 高可用性和灾难恢复:如果主服务器出现故障,从服务器可以升级为新的主服务器,确保数据库服务的连续性。
- 数据备份:从服务器可以用于定期备份数据,而不会影响主服务器的性能。
读写分离
数据库读写分离是一种数据库架构模式,旨在提高数据库性能、可伸缩性和可用性。它的基本原理是将数据库的读取操作(SELECT查询)和写入操作(INSERT、UPDATE、DELETE)分开,并将它们分配给不同的数据库实例。以下是数据库读写分离的原理:
1. 主数据库(Master)
- 主数据库是负责处理所有写入操作(INSERT、UPDATE、DELETE)的数据库实例。
- 主数据库上的数据是最新的,因为它是唯一执行写入操作的地方。
- 主数据库通常配置为较强大、高性能的服务器,以应对写入负载。
2. 从数据库(Slave)
- 从数据库是主数据库的副本,负责处理读取操作(SELECT查询)。
- 从数据库上的数据是主数据库的复制,通常是主数据库的数据的一个近似快照。
- 从数据库可以配置为多个实例,用于分担读取负载,提高性能。
3. 数据复制和同步
- 主数据库记录所有写入操作,将这些操作的结果记录到二进制日志(Binary Log)中。
- 从数据库连接到主数据库,请求复制主数据库上的二进制日志。
- 主数据库将二进制日志的内容传输给从数据库。
- 从数据库将接收到的二进制日志的内容逐一应用到自己的数据库,以保持与主数据库的同步。
- 从数据库的数据复制通常会有一定的延迟,但这不会影响主数据库上的写入操作。
4. 读写分离的负载均衡
- 通过将读取操作分配给从数据库,主数据库的负载减轻,因为写入操作通常比读取操作更消耗资源。
- 负载均衡可以通过在应用程序中实现,或者使用负载均衡代理来自动路由读取操作到不同的从数据库。
5. 写入操作的处理
- 所有写入操作必须发送到主数据库,以确保数据的一致性。
- 从数据库不允许进行写入操作,只负责读取操作。
6. 高可用性和灾难恢复
- 如果主数据库发生故障,可以将一个从数据库提升为新的主数据库,以确保数据库服务的连续性。
- 这提供了高可用性和灾难恢复的解决方案,因为数据在多个地方进行了备份。
数据库读写分离的优点包括提高性能、分担负载、提供冗余和灾难恢复,但需要注意冲突处理问题,因为写入操作可能在不同的数据库实例上引起冲突。此外,配置和管理读写分离需要详细了解数据库系统的特性和工具。
主从读写相关问题
问题1:master的写操作,slaves被动的进行一样的操作,保持数据一致性,那么slave是否可以主动的进行写操作?
假设slave可以主动的进行写操作,slave又无法通知master,这样就导致了master和slave数据不一致了。因此slave不应该进行写操作,至少是slave上涉及到复制的数据库不可以写。实际上,这里已经揭示了读写分离的概念。
问题2:主从复制中,可以有N个slave,可是这些slave又不能进行写操作,要他们干嘛?
实现数据备份:
类似于高可用的功能,一旦master挂了,可以让slave顶上去,同时slave提升为master。
异地容灾:比如master在北京,地震挂了,那么在上海的slave还可以继续。
主要用于实现scale out,分担负载,可以将读的任务分散到slaves上。
【很可能的情况是,一个系统的读操作远远多于写操作,因此写操作发向master,读操作发向slaves进行操作】
问题3:主从复制中有master,slave1,slave2,...等等这么多MySQL数据库,那比如一个JAVA WEB应用到底应该连接哪个数据库?
我们在应用程序中可以这样,insert/delete/update这些更新数据库的操作,用connection(for master)进行操作,
select用connection(for slaves)进行操作。那我们的应用程序还要完成怎么从slaves选择一个来执行select,例如使用简单的轮循算法。
这样的话,相当于应用程序完成了SQL语句的路由,而且与MySQL的主从复制架构非常关联,一旦master挂了,某些slave挂了,那么应用程序就要修改了。能不能让应用程序与MySQL的主从复制架构没有什么太多关系呢?
找一个组件,application program只需要与它打交道,用它来完成MySQL的代理,实现SQL语句的路由。
MySQL proxy并不负责,怎么从众多的slaves挑一个?可以交给另一个组件(比如haproxy)来完成。
这就是所谓的MySQL READ WRITE SPLITE,MySQL的读写分离。
问题4:如果MySQL proxy , direct , master他们中的某些挂了怎么办?
总统一般都会弄个副总统,以防不测。同样的,可以给这些关键的节点来个备份。
问题5:当master的二进制日志每产生一个事件,都需要发往slave,如果我们有N个slave,那是发N次,还是只发一次?如果只发一次,发给了slave-1,那slave-2,slave-3,...它们怎么办?
显 然,应该发N次。实际上,在MySQL master内部,维护N个线程,每一个线程负责将二进制日志文件发往对应的slave。master既要负责写操作,还的维护N个线程,负担会很重。可以这样,slave-1是master的从,slave-1又是slave-2,slave-3,...的主,同时slave-1不再负责select。 slave-1将master的复制线程的负担,转移到自己的身上。这就是所谓的多级复制的概念。
问题6:当一个select发往MySQL proxy,可能这次由slave-2响应,下次由slave-3响应,这样的话,就无法利用查询缓存了。
应该找一个共享式的缓存,比如memcache来解决。将slave-2,slave-3,这些查询的结果都缓存至mamcache中。
问题7:随着应用的日益增长,读操作很多,我们可以扩展slave,但是如果master满足不了写操作了,怎么办呢?
scale on ?更好的服务器? 没有最好的,只有更好的,太贵了。。。
scale out ? 主从复制架构已经满足不了。
可以分库【垂直拆分】,分表【水平拆分】。
四、 高并发环境解决方案
优化查询
- 使用合适的索引:确保数据库表上的查询字段有合适的索引,以加速检索操作。
- 避免全表扫描:尽量避免执行全表扫描,使用合适的条件来限制检索的数据范围。
- 使用合适的SQL语句:避免使用过于复杂或低效的SQL语句,优化查询以减少数据库负载。
数据库缓存
- 使用缓存:将频繁读取但不经常更新的数据缓存在内存中,例如使用缓存系统(如Redis)来存储常用数据,减轻数据库压力
- MySQL查询缓存:适用于相对静态数据,但在高并发情况下,它可能不太适用,因为缓存失效成本较高。
分库分表
- 水平分割数据:将大表分成小表,减小单表的数据量,以降低锁竞争和提高查询性能。
- 垂直分割数据:将表按照字段的访问频率分为多个表,以减少每个表的复杂性。
连接池
- 使用连接池:使用连接池来管理数据库连接,减少连接的创建和销毁开销,提高性能。
负载均衡
- 使用负载均衡器:通过负载均衡器将请求均匀分发给多个数据库服务器,以分担数据库服务器的负载。
数据库复制和主从复制
- 使用主从复制:配置数据库主从复制,将读操作分发到从服务器,以减轻主服务器的负担。
- 使用多个从服务器:在高并发环境中,可以使用多个从服务器以进一步分担负载。
事务优化
- 使用合适的事务隔离级别:根据需求选择合适的事务隔离级别,以平衡数据一致性和性能。
- 批量操作:将多个操作合并为一个事务,以减少事务的开销。
监控和调优
- 实时监控:使用数据库性能监控工具,实时监控数据库的性能,识别瓶颈和问题。
- 定期调优:基于监控数据,定期进行数据库的性能调优,优化查询计划、索引和硬件配置。
硬件升级
- 如果可能的话,升级数据库服务器的硬件,增加内存、CPU 和存储容量,以提高性能。
在高并发环境下,综合考虑这些解决方案,以及根据具体需求采取适当的措施,可以帮助提高 MySQL 数据库的性能和可用性,确保数据的一致性和完整性。