MySQL是一个关系型数据库管理系统,MySQL是开源免费的,并且方便扩展。默认端口3306。
关系型数据库:Oracle、DB2、Microsoft SQL Server、MySQL
关系型数据库,是指采用了关系模型来组织数据的数据库;关系型数据库的最大特点就是事务的一致性;支持SQL,可用于复杂的查询。
非关系型数据库:NoSql、Cloudant、MongoDb、redis、HBase
使用键值对存储数据;分布式;一般不支持ACID特性;基于键值对,数据没有耦合性,容易扩展;不提供sql支持,学习和使用成本较高
第一范式:每个列都不可以再拆分。
第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。
第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。
设计数据库结构要尽量遵守三范式,如果不遵守,必须有足够的理由。比如为了性能而妥协数据库的设计。
权限表用来控制用户对数据库的访问。放在mysql数据库里,由mysql_install_db脚本初始化
MySQL 当前默认的存储引擎是InnoDB,所有的存储引擎中只有 InnoDB 是事务性存储引擎。MyISAM不支持事务和行级锁,而且最大的缺陷就是崩溃后无法安全恢复。
MySOL存储引擎和MyISAM区别:
MyISAM索引与InnoDB索引的区别?
存储引擎选择
如果没有特别的需求,使用默认的Innodb即可。
MyISAM:做很多count的计算,读密集,没有事务。比如博客系统、新闻门户网站。
Innodb:要求事务和外键,写密集,高并发。比如OA自动化办公系统。
插入缓冲(insert buffer)
二次写(double write)
自适应哈希索引(ahi)
预读(read ahead)
索引是一种特殊的文件,包含数据表里所有记录的引用指针,占据物理存储空间。
索引是一种排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。
索引优缺点:
(1) 优点:加快检索速度
(2)缺点:(a)创建索引和维护索引需要耗费时间(b)索引需要占用空间 ©进行数据的增删改时候需要动态维护索引
索引的数据结构主要有BTree索引 和 哈希索引:
哈希索引底层的数据结构就是哈希表,绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;但是存在一些缺点:
1、不能使用范围查询和模糊查询。2、无法避免任何排序运算;3、不支持多列联合索引的最左匹配规则;4、任何时候都不能避免表扫描。5、存在所谓的哈希碰撞问题。
其余大部分场景,建议选择BTree索引:
1、B+树的层级更少:相较于B树,B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;
2、B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;
3、B+树具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询区间数据时更方便,缓存的命中率也会比B树高。
4、B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树的非叶子节点存有关键字数据,这时会要比B+树快。
主键索引: 数据列不允许重复,不允许为NULL,一个表只能有一个主键。
唯一索引: 数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。
可以通过 ALTER TABLE table_name ADD UNIQUE (column); 创建唯一索引
可以通过 ALTER TABLE table_name ADD UNIQUE (column1,column2); 创建唯一组合索引
普通索引: 基本的索引类型,没有唯一性的限制,允许为NULL值。
可以通过ALTER TABLE table_name ADD INDEX index_name (column);创建普通索引
可以通过ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);创建组合索引
全文索引: 是目前搜索引擎使用的一种关键技术。
可以通过ALTER TABLE table_name ADD FULLTEXT (column);创建全文索引
把无序的数据变成有序的查询:
索引虽好,但也不是无限制的使用,最好符合一下几个原则
1) 最左前缀匹配原则。mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
2)较频繁作为查询条件的字段才去创建索引,更新频繁字段不适合创建索引,重复值比较多的列不要建立索引。
3)若是不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低)
5)尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
6)定义有外键的数据列一定要建立索引。
7)对于定义为text、image和bit的数据类型的列不要建立索引。
第一种方式:在执行CREATE TABLE时创建索引
第二种方式:使用ALTER TABLE命令去增加索引
第三种方式:使用CREATE INDEX命令创建
CREATE TABLE user_index2 (
id INT auto_increment PRIMARY KEY,
first_name VARCHAR (16),
last_name VARCHAR (16),
id_card VARCHAR (18),
information text,
KEY name (first_name, last_name),
FULLTEXT KEY (information),
UNIQUE KEY (id_card)
);
#ALTER TABLE用来创建普通索引、UNIQUE索引或PRIMARY KEY索引。
ALTER TABLE table_name ADD INDEX index_name (column_list);
#CREATE INDEX可对表增加普通索引或UNIQUE索引。(但是,不能创建PRIMARY KEY索引)
CREATE INDEX index_name ON table_name (column_list);
删除索引
根据索引名删除普通索引、唯一索引、全文索引:alter table 表名 drop KEY 索引名
关于索引:对数据增删改都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增/改/删的执行效率。所以,在我们删除数据库百万级别数据的时候,查询MySQL官方手册得知删除数据的速度和创建的索引数量是成正比的。
所以我们想要删除百万数据的时候可以先删除索引(此时大概耗时三分多钟)
然后删除其中无用数据(此过程需要不到两分钟)
删除完成后重新创建索引(此时数据较少了)创建索引也非常快,约十分钟左右。
与之前的直接删除绝对是要快速很多,更别说万一删除中断,一切删除会回滚。
创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。
最左前缀匹配原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据
非聚簇索引:将数据和索引分开存储,索引结构的叶子节点为数据的引用地址,myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时,在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在key buffer命中时,速度慢的原因
事务是逻辑上的一组操作,要么都执行,要么都不执行。
比如转账就是一个事务操作。
假如小明要给小红转账1000元,**涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。**万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。
事物的四大特性(ACID)
原子性: 事务是最小的执行单位,不允许分割。确保动作要么全部完成,要么都不完成;
一致性: 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;
隔离性: 并发访问数据库时,一个事务不被其他事务所干扰,各并发事务之间数据库是独立的;
持久性: 事务提交后对数据库的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
什么是脏读?幻读?不可重复读?
脏读:一个事务读取了另一个事务未提交的数据。 某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读:在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间数据被另一事务修改。
幻读: 在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入或删除几列数据。
事务的隔离级别?MySQL的默认隔离级别是什么?
Mysql 默认采用的 REPEATABLE_READ隔离级别
Oracle 默认采用的 READ_COMMITTED隔离级别
数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序
隔离级别与锁的关系
在Read Uncommitted级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突(加了共享锁,其他事务就不能获得排它锁对数据进行修改)
在Read Committed级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁(保证事务在读数据的时候,其他事务不能修改数据)
在Repeatable Read级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁。(保证事务提交前后保持一致)
SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。
按锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。
行级锁:
行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁 和 排他锁。
特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
表级锁
表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。
特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。
页级锁
页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。
特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
从锁的类别上,有共享锁和排他锁。
共享锁:
又叫读锁。 是读取操作的锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。
排他锁:
又叫写锁。 ,如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。
乐观锁:
在访问数据之前,默认去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。
实现方式:版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是CAS实现的。
悲观锁:
假定会发生并发冲突,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)
实现方式:使用数据库中的锁机制,Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
版本号机制
一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。
CAS算法
即compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。
CAS算法涉及到三个操作数
1)需要读写的内存值 V
2) 进行比较的值 A
3)拟写入的新值 B
当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试。
乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。
但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。
数据定义语言DDL(Data Ddefinition Language) CREATE,DROP,ALTER
数据查询语言DQL(Data Query Language) SELECT
数据操纵语言DML(Data Manipulation Language) INSERT,UPDATE,DELETE
数据控制功能DCL(Data Control Language) GRANT,REVOKE,COMMIT,ROLLBACK
int(10) 的10表示显示的数据的长度,不是存储数据的大小;
chart(10)和varchar(10) 的10表示存储数据的大小,即表示存储多少个字符。
int(10) 10位的数据长度 9999999999,占32个字节,int型4位
char(10) 10位固定字符串,不足补空格 最多10个字符
varchar(10) 10位可变字符串,不足补空格 最多10个字符
char(10)表示存储定长的10个字符,不足10个就用空格补齐,占用更多的存储空间,但空格不算一个字符
varchar(10)表示存储10个变长的字符,存储多少个就是多少个,空格也按一个字符存储,这一点是和char(10)的空格不同的,char(10)的空格表示占位不算一个字符
Explain 包含字段信息如下: id、select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、filtered、Extra 12个字段。
id:
表示查询中执行select子句或者操作表的顺序,id的值越大,代表优先级越高,越先执行。
select_type:
表示 select 查询的类型,主要是用于区分各种复杂的查询,例如:普通查询、联合查询、子查询
1、SIMPLE
表示最简单的 select 查询语句,在查询中不包含子查询或者 union交并差集等操作。
2、PRIMARY
当查询语句中包含任何复杂的子部分,最外层查询则被标记为PRIMARY。
3、SUBQUERY
当 select 或 where 列表中包含了子查询,该子查询被标记为:SUBQUERY 。
4、DERIVED
表示包含在from子句中的子查询的select,在我们的 from 列表中包含的子查询
5、UNION
如果union后边又出现的select 语句,则会被标记为union;若 union 包含在 from 子句的子查询中,外层 select 将被标记为 derived。
6、UNION RESULT
UNION RESULT:代表从union的临时表中读取数据,而table列的
table
查询的表名,并不一定是真实存在的表,有别名显示别名,也可能为临时表,例如上边的DERIVED、
partitions
查询时匹配到的分区信息,对于非分区表值为NULL,当查询的是分区表时,partitions显示分区表命中的分区情况。
type
查询使用了何种类型,在表中找到所需行的方式。它在 SQL优化中是一个非常重要的指标,以下性能从好到坏依次是:system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
1、system
当表仅有一行记录时(系统表),数据量很少,往往不需要进行磁盘IO,速度非常快。
2、const
表示查询时命中 primary key 主键或者 unique 唯一索引,或者被连接的部分是一个常量(const)值。这类扫描效率极高,返回数据量少,速度非常快。
3、eq_ref
查询时命中主键primary key 或者 unique key索引,就是 eq_ref。
4、ref
区别于eq_ref ,ref表示使用非唯一性索引,会找到很多个符合条件的行。
5、ref_or_null
这种连接类型类似于 ref,区别在于 MySQL会额外搜索包含NULL值的行。
6、index_merge
使用了索引合并优化方法,查询使用了两个以上的索引。
7、unique_subquery
替换下面的 IN子查询,子查询返回不重复的集合。
8、index_subquery
区别于unique_subquery,用于非唯一索引,可以返回重复值。
9、range
使用索引选择行,仅检索给定范围内的行。简单点说就是针对一个有索引的字段,给定范围检索数据。在where语句中使用 bettween…and、<、>、<=、in 等条件查询 type 都是 range。
10、index
Index 与ALL 其实都是读全表,区别在于index是遍历索引树读取,而ALL是从硬盘中读取。
11、ALL
将遍历全表以找到匹配的行,性能最差。
possible_keys
指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用
Key
显示MySQL实际决定使用的键(索引),必然包含在possible_keys中
key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)
ref
列与索引的比较,表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
常见的有:const,func,null,字段名。
当使用常量等值查询,显示const,
当关联查询时,会显示相应关联表的关联字段
如果查询条件使用了表达式、函数,或者条件列发生内部隐式转换,可能显示为func
其他情况null
rows
估算出结果集行数,表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数、
extra 的信息非常丰富,常见的有:
Using index 使用覆盖索引
Using where 使用了用where子句来过滤结果集
Using filesort 使用文件排序,使用非索引列进行排序时出现,非常消耗性能,尽量优化。
Using temporary 使用了临时表 sql优化的目标可以参考阿里开发手册
SQL性能优化的目标:至少要达到 range 级别,要求是ref级别,如果可以是consts最好。
说明:
1) consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。
2) ref 指的是使用普通的索引(normal index)。
3) range 对索引进行范围检索。
反例:explain表的结果,type=index,索引物理文件全扫描,速度非常慢,这个index级别比较range还低,与全表扫描是小巫见大巫。
利用延迟关联或者子查询优化超多分页场景。
说明:MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行,那当offset特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。
正例:先快速定位需要获取的id段,然后再关联:
SELECT a.* FROM 表1 a, (select id from 表1 where 条件 LIMIT 100000,20 ) b where a.id=b.id
用于记录执行时间超过某个临界值的SQL日志,用于快速定位慢查询,为我们的优化做参考。
可以使用show variables like ‘slow_query_log’查看是否开启,如果状态值为OFF,可以使用set GLOBAL slow_query_log = on来开启,它会在datadir下产生一个xxx-slow.log的文件。
实操时应该从长时间设置到短的时间,即将最慢的SQL优化掉
查看日志,一旦SQL超过了我们设置的临界时间就会被记录到xxx-slow.log中
慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?
所以优化也是针对这三个方向来的,
主键是数据库确保数据行唯一性的保障。设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全。
主键使用自增ID,不要使用UUID。
在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的插入,移动操作,然后导致产生很多的内存碎片,造成性能的下降。
关于主键是聚簇索引,如果没有主键,InnoDB会选择一个唯一键来作为聚簇索引,如果没有唯一键,会生成一个隐式的主键。
确定ON或者USING子句中是否有索引。
确保GROUP BY和ORDER BY只有一个表中的列,这样MySQL才有可能使用索引。
用关联查询替代
优化GROUP BY和DISTINCT
这两种查询据可以使用索引来优化,是最有效的优化方法
关联查询中,使用标识列分组的效率更高
如果不需要ORDER BY,进行GROUP BY时加ORDER BY NULL,MySQL不会再进行文件排序。
WITH ROLLUP超级聚合,可以挪到应用程序处理
LIMIT偏移量大的时候,查询效率较低
可以记录上次查询的最大ID,下次查询时直接根据该ID来查询
优化UNION查询
UNION ALL的效率高于UNION
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
-- 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=
3.应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
4.应尽量避免在 where 子句中使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
-- 可以这样查询:
select id from t where num=10 union all select id from t where num=20
5.in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
-- 对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
7.如果在 where 子句中使用参数,也会导致全表扫描。
6.下面的查询也将导致全表扫描:select id from t where name like ‘%李%’若要提高效率,可以考虑全文检索。
8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
1、根据最左前缀原则,我们一般把排序分组频率最高的列放在最左边
2、模糊查询以%为开始的查询,只能使用全文索引来进行优化。
3、使用短索引。如果可能应该指定一个前缀长度。
group by语法可以根据给定数据列的每个成员对查询结果进行分组统计,最终得到一个分组汇总表。
SELECT DEPT, MAX(SALARY) AS MAXIMUM FROM STAFF GROUP BY DEPT :每个部分的最高薪水
SELECT DEPT, sum( SALARY ) AS total FROM STAFF GROUP BY DEPT,每个部门的总薪水
having字句可以让我们筛选成组后的各种数据,where字句在聚合前先筛选记录,也就是说作用在group by和having字句前。而 having子句在聚合后对组记录进行筛选。我的理解就是真实表中没有此数据,这些数据是通过一些函数生成。
SELECT region, SUM(population), SUM(area) FROM bbc GROUP BY region HAVING SUM(area)>1000000
SELECT DEPT, MAX( SALARY ) AS MAXIMUM, MIN( SALARY ) AS MINIMUM FROM staff GROUP BY DEPT
HAVING COUNT( * ) >2 ORDER BY DEPT
查询最近N天(不超过30天)某一款产品的订单。从第10条开始取5条,ID从大到小倒序。
select * from table limit 9,5;#从0开始
写代码 创建索引
CREATE (UNIQUE/FULLTEXT/) INDEX indexName ON mytable(username(length));
ALTER table tableName ADD INDEX indexName(columnName);
CREATE TABLE mytable(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
INDEX [indexName] (username(length)) );
主从复制:将主数据库中的DDL和DML操作通过二进制日志(BINLOG)传输到从数据库上,然后将这些日志重新执行(重做);从而使得从数据库的数据与主数据库保持一致。
主从复制的作用:
MySQL主从复制解决的问题
数据分布:随意开始或停止复制,并在不同地理位置分布数据备份
负载均衡:降低单个服务器的压力
高可用和故障切换:帮助应用程序避免单点失败
升级测试:可以用更高版本的MySQL作为从库
MySQL主从复制工作原理
基本原理流程,3个线程以及之间的关联
主:binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中;
从:io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进自己的relay log中;
从:sql执行线程——执行relay log中的语句;
复制过程:
1、主节点log dump线程:当从节点连接主节点时,主节点会创建一个log dump 线程,用于发送bin-log的内容。在读取bin-log中的操作时,此线程会对主节点上的bin-log加锁,当读取完成,甚至在发动给从节点之前,锁会被释放。
2、从节点I/O线程:当从节点上执行start slave
命令之后,从节点会创建一个I/O线程用来连接主节点,请求主库中更新的bin-log。I/O线程接收到主节点bin log dump 进程发来的更新之后,保存在本地relay-log中。
3、从节点SQL线程:SQL线程负责读取relay log中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。
异步复制:主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理;主节点不会主动push bin log到从节点;
半同步模式:这种模式下主节点只需要接收到其中一台从节点的返回信息,就会commit;否则需要等待直到超时时间然后切换成异步模式再提交;这样做的目的可以使主从数据库的数据延迟缩小,可以提高数据安全性。半同步模式不是mysql内置的,需要装插件开启半同步模式。
全同步模式:全同步模式是指主节点和从节点全部执行了commit并确认才会向客户端返回成功。
解决方法:
半同步复制—解决数据丢失的问题
并行复制—-解决从库复制延迟的问题(并行是指从库多线程apply binlog库级别并行应用binlog,同一个库数据更改还是串行的(5.7版并行复制基于事务组)设置)