体系结构的概念
任何一套系统当中,每个部件都能起到一定的作用!MySQL的体系结构
体系结构详解
客户端连接 支持接口:支持的客户端连接,例如C、Java、PHP等语言来连接MySQL数据库 第一层:网络连接层 连接池:管理、缓冲用户的连接,线程处理等需要缓存的需求。例如:当客户端发送一个请求连接,会从连接池中获取一个连接进行使用。 第二层:核心服务层 管理服务和工具:系统的管理和控制工具,例如备份恢复、复制、集群等。SQL接口:接受SQL命令,并且返回查询结果。查询解析器:验证和解析SQL命令,例如过滤条件、语法结构等。查询优化器:在执行查询之前,使用默认的一套优化机制进行优化sql语句缓存:如果缓存当中有想查询的数据,则直接将缓存中的数据返回。没有的话再重新查询! 第三层:存储引擎层 插件式存储引擎:管理和操作数据的一种机制,包括(存储数据、如何更新、查询数据等) 第四层:系统文件层 文件系统:配置文件、数据文件、日志文件、错误文件、二进制文件等等的保存引擎的概念
生活中,引擎就是整个机器运行的核心,不同的引擎具备不同的功能。MySQL存储引擎的概念
MySQL数据库使用不同的机制存取表文件 , 机制的差别在于不同的存储方式、索引技巧、锁定水平以及广泛的不同的功能和能力,在MySQL中 , 将这些不同的技术及配套的功能称为存储引擎在关系型数据库中数据的存储是以表的形式存进行储的,所以存储引擎也可以称为表类型(即存储和操作此表的类型)。Oracle , SqlServer等数据库只有一种存储引擎 , 而MySQL针对不同的需求, 配置MySQL的不同的存储引擎 , 就会让数据库采取了不同的处理数据的方式和扩展功能。通过选择不同的引擎 ,能够获取最佳的方案 , 也能够获得额外的速度或者功能,提高程序的整体效果。所以了解引擎的特性 , 才能贴合我们的需求 , 更好的发挥数据库的性能。MySQL支持的存储引擎
MySQL5.7支持的引擎包括:InnoDB、MyISAM、MEMORY、Archive、Federate、CSV、BLACKHOLE等其中较为常用的有三种:InnoDB、MyISAM、MEMORY查找顺序:
模拟查找15的过程 : 1.根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】 比较关键字15在区间(<17),找到磁盘块1的指针P1。 2.P1指针找到磁盘块2,读入内存。【磁盘I/O操作第2次】 比较关键字15在区间(>12),找到磁盘块2的指针P3。 3.P3指针找到磁盘块7,读入内存。【磁盘I/O操作第3次】 在磁盘块7中找到关键字15。 -- 分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。 -- 由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个BTree查找效率的决定因素。BTree使用较少的节点个数,使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。B+Tree是在BTree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎就是用B+Tree实现其索引结构。
从上一节中的BTree结构图中可以看到每个节点中不仅包含数据的key值,还有data值。而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。
B+Tree相对于BTree区别:
非叶子节点只存储键值信息。所有叶子节点之间都有一个连接指针。数据记录都存放在叶子节点中。将上一节中的BTree优化,由于B+Tree的非叶子节点只存储键值信息,假设每个磁盘块能存储4个键值及指针信息,则变成B+Tree后其结构如下图所示: 通常在B+Tree上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。因此可以对B+Tree进行两种查找运算:
【有范围】对于主键的范围查找和分页查找
【有顺序】从根节点开始,进行随机查找
实际情况中每个节点可能不能填充满,因此在数据库中,B+Tree的高度一般都在24层。MySQL的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要13次磁盘I/O操作。
索引的设计可以遵循一些已有的原则,创建索引的时候请尽量考虑符合这些原则,便于提升索引的使用效率,更高效的使用索引。
创建索引时的原则 对查询频次较高,且数据量比较大的表建立索引。使用唯一索引,区分度越高,使用索引的效率越高。索引字段的选择,最佳候选列应当从where子句的条件中提取,如果where子句中的组合比较多,那么应当挑选最常用、过滤效果最好的列的组合。使用短索引,索引创建之后也是使用硬盘来存储的,因此提升索引访问的I/O效率,也可以提升总体的访问效率。假如构成索引的字段总长度比较短,那么在给定大小的存储块内可以存储更多的索引值,相应的可以有效的提升MySQL访问索引的I/O效率。索引可以有效的提升查询数据的效率,但索引数量不是多多益善,索引越多,维护索引的代价自然也就水涨船高。对于插入、更新、删除等DML操作比较频繁的表来说,索引过多,会引入相当高的维护代价,降低DML操作的效率,增加相应操作的时间消耗。另外索引过多的话,MySQL也会犯选择困难病,虽然最终仍然会找到一个可用的索引,但无疑提高了选择的代价。 联合索引的特点在mysql建立联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配, 对列name列、address和列phone列建一个联合索引
ALTER TABLE user ADD INDEX index_three(name,address,phone);联合索引index_three实际建立了(name)、(name,address)、(name,address,phone)三个索引。所以下面的三个SQL语句都可以命中索引。
SELECT * FROM user WHERE address = '北京' AND phone = '12345' AND name = '张三'; SELECT * FROM user WHERE name = '张三' AND address = '北京'; SELECT * FROM user WHERE name = '张三';上面三个查询语句执行时会依照最左前缀匹配原则,检索时分别会使用索引
(name,address,phone) (name,address) (name)进行数据匹配。
索引的字段可以是任意顺序的,如:
-- 优化器会帮助我们调整顺序,下面的SQL语句都可以命中索引 SELECT * FROM user WHERE address = '北京' AND phone = '12345' AND name = '张三';Mysql的优化器会帮助我们调整where条件中的顺序,以匹配我们建立的索引。
联合索引中最左边的列不包含在条件查询中,所以根据上面的原则,下面的SQL语句就不会命中索引。
-- 联合索引中最左边的列不包含在条件查询中,下面的SQL语句就不会命中索引 SELECT * FROM user WHERE address = '北京' AND phone = '12345';之前我们学习过多线程,多线程当中如果想保证数据的准确性是如何实现的呢?没错,通过同步实现。同步就相当于是加锁。加了锁以后有什么好处呢?当一个线程真正在操作数据的时候,其他线程只能等待。当一个线程执行完毕后,释放锁。其他线程才能进行操作!
那么我们的MySQL数据库中的锁的功能也是类似的。在我们学习事务的时候,讲解过事务的隔离性,可能会出现脏读、不可重复读、幻读的问题,当时我们的解决方式是通过修改事务的隔离级别来控制,但是数据库的隔离级别呢我们并不推荐修改。所以,锁的作用也可以解决掉之前的问题!
锁机制 : 数据库为了保证数据的一致性,而使用各种共享的资源在被并发访问时变得有序所设计的一种规则。
举例,在电商网站购买商品时,商品表中只存有1个商品,而此时又有两个人同时购买,那么谁能买到就是一个关键的问题。
这里会用到事务进行一系列的操作:
先从商品表中取出物品的数据然后插入订单付款后,再插入付款表信息更新商品表中商品的数量以上过程中,使用锁可以对商品数量数据信息进行保护,实现隔离,即只允许第一位用户完成整套购买流程,而其他用户只能等待,这样就解决了并发中的矛盾问题。
在数据库中,数据是一种供许多用户共享访问的资源,如何保证数据并发访问的一致性、有效性,是所有数据库必须解决的一个问题,MySQL由于自身架构的特点,在不同的存储引擎中,都设计了面对特定场景的锁定机制,所以引擎的差别,导致锁机制也是有很大差别的。
悲观锁的概念
就是很悲观,它对于数据被外界修改的操作持保守态度,认为数据随时会修改。整个数据处理中需要将数据加锁。悲观锁一般都是依靠关系型数据库提供的锁机制。我们之前所学的行锁,表锁不论是读写锁都是悲观锁。乐观锁的概念
就是很乐观,每次自己操作数据的时候认为没有人会来修改它,所以不去加锁。但是在更新的时候会去判断在此期间数据有没有被修改。需要用户自己去实现,不会发生并发抢占资源,只有在提交操作的时候检查是否违反数据完整性。悲观锁和乐观锁使用前提
对于读的操作远多于写的操作的时候,这时候一个更新操作加锁会阻塞所有的读取操作,降低了吞吐量。最后还要释放锁,锁是需要一些开销的,这时候可以选择乐观锁。如果是读写比例差距不是非常大或者系统没有响应不及时,吞吐量瓶颈的问题,那就不要去使用乐观锁,它增加了复杂度,也带来了业务额外的风险。这时候可以选择悲观锁。乐观锁的实现方式
版本号
给数据表中添加一个version列,每次更新后都将这个列的值加1。读取数据时,将版本号读取出来,在执行更新的时候,比较版本号。如果相同则执行更新,如果不相同,说明此条数据已经发生了变化。用户自行根据这个通知来决定怎么处理,比如重新开始一遍,或者放弃本次更新。 -- 创建city表 CREATE TABLE city( id INT PRIMARY KEY AUTO_INCREMENT, -- 城市id NAME VARCHAR(20), -- 城市名称 VERSION INT -- 版本号 ); -- 添加数据 INSERT INTO city VALUES (NULL,'北京',1),(NULL,'上海',1),(NULL,'广州',1),(NULL,'深圳',1); -- 修改北京为北京市 -- 1.查询北京的version SELECT VERSION FROM city WHERE NAME='北京'; -- 2.修改北京为北京市,版本号+1。并对比版本号 UPDATE city SET NAME='北京市',VERSION=VERSION+1 WHERE NAME='北京' AND VERSION=1;时间戳
和版本号方式基本一样,给数据表中添加一个列,名称无所谓,数据类型需要是timestamp每次更新后都将最新时间插入到此列。读取数据时,将时间读取出来,在执行更新的时候,比较时间。如果相同则执行更新,如果不相同,说明此条数据已经发生了变化。表锁和行锁
行锁:锁的粒度更细,加行锁的性能损耗较大。并发处理能力较高。InnoDB引擎默认支持!表锁:锁的粒度较粗,加表锁的性能损耗较小。并发处理能力较低。InnoDB、MyISAM引擎支持!InnoDB锁优化建议
尽量通过带索引的列来完成数据查询,从而避免InnoDB无法加行锁而升级为表锁。
合理设计索引,索引要尽可能准确,尽可能的缩小锁定范围,避免造成不必要的锁定。
尽可能减少基于范围的数据检索过滤条件。
尽量控制事务的大小,减少锁定的资源量和锁定时间长度。
在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率。
对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁的产生。
下载地址 : http://dl.mycat.io/ 选择1.6.7.1的版本,下载到D盘,安装包入下图: 上传:使用SecureCRT的SFTP命令,将文件发送到Linux虚拟机root目录下:
sftp> put D:\Mycat-server-1.6.7.1-release-20190627191042-linux.tar.gz解压:解压mycat.tar.gz并查看
tar -zxvf mycat.tar.gz cd mycat ll授权:设置mycat权限
chmod -R 777 mycat环境变量:配置环境变量
vi /etc/profile // 添加 export MYCAT_HOME=/root/mycat // 使环境变量生效 source /etc/profile启动mycat
// 进入bin目录 [root@localhost]# cd /root/mycat/bin // 执行启动命令 [root@localhost bin]# ./mycat start查看:检测端口监听状况,Mycat的端口号是8066
[root@localhost bin]# netstat -ant|grep 8066连接:使用SQLYog连接Mycat (注意如果用Navicat可能会因为版本的问题链接不上,用SQLYog)
连接后显示:
克隆虚拟机
修改配置网卡 在第二个虚拟机中,生成全新mac地址
重启网络
// 重启网络 service network restart //查看ip地址 ip addr修改mysql配置文件,更改uuid
在第二个服务器上,修改mysql的uuid // 编辑配置文件 vi /var/lib/mysql/auto.cnf // 将server-uuid更改启动MySQL并查看
//将两台服务器的防火墙关闭 systemctl stop firewalld //启动两台服务器的mysql service mysqld restart //启动两台服务器的mycat cd /root/mycat/bin ./mycat restart //查看监听端口 netstat -ant|grep 3306 netstat -ant|grep 8066 //使用sqlyog测试连接1mycat通过主机链接从机的时候记得授权能远程登录 授予远程连接权限 //授权 grant all privileges on . to ‘root’ @’%’ identified by ‘密码’; //刷新 flush privileges; 2网卡注意值留一个,链接
主从复制的概念
为了使用Mycat进行读写分离,我们先要配置MySQL数据库的主从复制。
从服务器自动同步主服务器的数据,从而达到数据一致。
进而,我们可以写操作时,只操作主服务器,而读操作,就可以操作从服务器了。
原理:主服务器在处理数据时,生成binlog日志,通过对日志的备份,实现从服务器的数据同步。
主服务器的配置
在第一个服务器上,编辑mysql配置文件 // 编辑mysql配置文件 vi /etc/my.cnf //在[mysqld]下面加上: log-bin=mysql-bin # 开启复制操作 server-id=1 # master is 1 innodb_flush_log_at_trx_commit=1 sync_binlog=1 登录mysql,创建用户并授权 // 登录mysql mysql -u root -p // 去除密码权限 SET GLOBAL validate_password_policy=0; SET GLOBAL validate_password_length=1; // 创建用户 CREATE USER 'hm'@'%' IDENTIFIED BY 'itheima'; // 授权 GRANT ALL ON *.* TO 'hm'@'%'; 重启mysql服务,登录mysql服务 // 重启mysql service mysqld restart // 登录mysql mysql -u root -p 查看主服务器的配置 // 查看主服务器配置 show master status;从服务器的配置
在第二个服务器上,编辑mysql配置文件 // 编辑mysql配置文件 vi /etc/my.cnf // 在[mysqld]下面加上: server-id=2 登录mysql // 登录mysql mysql -u root -p // 执行 use mysql; drop table slave_master_info; drop table slave_relay_log_info; drop table slave_worker_info; drop table innodb_index_stats; drop table innodb_table_stats; source /usr/share/mysql/mysql_system_tables.sql; 重启mysql,重新登录,配置从节点 // 重启mysql service mysqld restart // 重新登录mysql mysql -u root -p // 执行 change master to master_host='主服务器ip地址',master_port=3306,master_user='hm',master_password='itheima',master_log_file='mysql-bin.000001',master_log_pos=4642; 重启mysql,重新登录,开启从节点 // 重启mysql service mysqld restart // 重新登录mysql mysql -u root -p // 开启从节点 start slave; // 查询结果 show slave status\G; //Slave_IO_Running和Slave_SQL_Running都为yes才表示同步成功。测试
sqlyog连接主服务器 -- 主服务器创建db1数据库,从服务器会自动同步 CREATE DATABASE db1; sqlyog连接从服务器 -- 从服务器创建db2数据库,主服务器不会自动同步 CREATE DATABASE db2;启动失败的解决方案
启动失败:Slave_IO_Running为 NO 方法一:重置slave slave stop; reset slave; start slave ; 方法二:重设同步日志文件及读取位置 slave stop; change master to master_log_file=’mysql-bin.000001’, master_log_pos=1; start slave ;读写分离的概念
写操作只写入主服务器,读操作读取从服务器。在主服务器上修改server.xml
user标签主要用于定义登录mycat的用户和权限。如上面定义用户名mycat和密码123456,该用户可以访问的schema的HEIMADB逻辑库。 <user name="root" defaultAccount="true"> <property name="password">123456</property> <property name="schemas">HEIMADB</property> <!-- 表级 DML 权限设置 --> <!-- <privileges check="false"> <schema name="TESTDB" dml="0110" > <table name="tb01" dml="0000"></table> <table name="tb02" dml="1111"></table> </schema> </privileges> --> </user> 在主服务器上修改schema.xml <?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="HEIMADB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema> <dataNode name="dn1" dataHost="localhost1" database="db1" /> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- 主服务器进行写操作 --> <writeHost host="hostM1" url="localhost:3306" user="root" password="itheima"> <!-- 从服务器负责读操作 --> <readHost host="hostS1" url="192.168.203.135:3306" user="root" password="itheima" /> </writeHost> </dataHost> </mycat:schema>配置详解
schema标签逻辑库的概念和mysql数据库中Datebase的概念相同,我们在查询这两个逻辑库中的表的时候,需要切换到该逻辑库下才可以查到所需要的表。
dataNode属性:该属性用于绑定逻辑库到某个具体的database上。
dataNode标签: dataNode标签定义了mycat中的数据节点,也就是数据分片。一个dataNode标签就是一个独立的数据分片。
name属性:定义数据节点的名字,这个名字需要是唯一的,我们需要在table标签上应用这个名字,来建立表与分片对应的关系。
dataHost属性:该属性用于定义该分片属于那个数据库实例,属性值是引用datahost标签定义的name属性。
database属性:该属性用于定义该分片属于那个具体数据库实例上的具体库,因为这里使用两个纬度来定义分片,就是:实例+具体的库。因为每个库上建立的表和表结构是一样的。所以这样做就可以轻松的对表进行水平拆分。
dataHost标签:该标签在mycat逻辑库中也是作为最底层的标签存在,直接定义了具体的数据库实例、读写分离配置和心跳语句。
balance属性: 负载均衡类型 balance=0: 不开启读写分离,所有读操作都发送到当前可用的writeHost上。 balance=1: 全部的readHost与Stand by writeHost都参与select语句的负载均衡 balance=2: 所有的读操作都随机在writeHost,readHost上分发。 balance=3: 所有的读请求都随机分配到writeHost对应的readHost上执行,writeHost不负担读压力。
switchType属性: -1:表示不自动切换。 1 :默认值,表示自动切换 2:表示基于MySQL主从同步状态决定是否切换,心跳语句: show slave status. 3:表示基于mysql galary cluster的切换机制,适合mycat1.4之上的版本,心跳语句show status like “%esrep%”;
writeHost标签,readHost标签:这两个标签指定后端数据库的相关配置给mycat,用于实例化后端连接池。唯一不同的是,writeHost指定写实例、readHost指定读实例,组合这些读写实例来满足系统的要求。
host属性:用于标识不同的实例,对于writehost,一般使用M1;对于readhost一般使用S1.url属性:后端实例连接地址,如果使用native的dbDriver,则一般为address:port这种形式,用JDBC或其他的dbDriver,则需要特殊指定。当使用JDBC时则可以这么写:jdbc:mysql://localhost:3306/。user属性:后端存储实例的用户名。password属性:后端存储实例的密码测试
重启主服务器的mycat // 重启mycat cd /root/mycat/bin ./mycat restart // 查看端口监听 netstat -ant|grep 8066 sqlyog连接mycat -- 创建学生表 CREATE TABLE student( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10) ); -- 查询学生表 SELECT * FROM student; -- 添加两条记录 INSERT INTO student VALUES (NULL,'张三'),(NULL,'李四'); -- 停止主从复制后,添加的数据只会保存到主服务器上。 INSERT INTO student VALUES (NULL,'王五'); sqlyog连接主服务器 -- 主服务器:查询学生表,可以看到数据 SELECT * FROM student; sqlyog连接从服务器 -- 从服务器:查询学生表,可以看到数据(因为有主从复制) SELECT * FROM student; -- 从服务器:删除一条记录。(主服务器并没有删除,mycat中间件查询的结果是从服务器的数据) DELETE FROM student WHERE id=2;分库分表的概念
将庞大的数据进行拆分水平拆分:根据表的数据逻辑关系,将同一表中的数据按照某种条件,拆分到多台数据库服务器上,也叫做横向拆分。例如:一张1000万的大表,按照一模一样的结构,拆分成4个250万的小表,分别保存到4个数据库中。垂直拆分:根据业务的维度,将不同的表切分到不同的数据库之上,也叫做纵向拆分。例如:所有的订单都保存到订单库中,所有的用户都保存到用户库中,同类型的表保存在同一库,不同的表分散在不同的库中。Mycat水平拆分
修改主服务器的server.xml
0:本地文件方式
在mycat/conf/sequence_conf.properties文件中: GLOBAL.MINDI=10000最小值 GLOBAL.MAXID=20000最大值,建议修改到9999999999
1:数据库方式
分库分表中保证全局主键自增唯一,但是需要执行mycat函数,配置sequence_db_conf.properties
2:时间戳方式
mycat实现的时间戳,建议varchar类型,要注意id的长度
<!-- 修改主键的方式 --> <property name="sequnceHandlerType">0</property> 修改主服务器的sequence_conf.properties #default global sequence GLOBAL.HISIDS= # 可以自定义关键字 GLOBAL.MINID=10001 # 最小值 GLOBAL.MAXID=20000 # 最大值 GLOBAL.CURID=10000 修改主服务器的schema.xml table标签定义了逻辑表,所有需要拆分的表都需要在这个标签中定义。rule属性:拆分规则。mod-long是拆分规则之一,主键根据服务器数量取模,在rule.xml中指定。如果是3个数据库,那么数据取模后,平均分配到三个库中。name属性:定义逻辑表的表名,这个名字就如同在数据库中执行create table命令指定的名字一样,同一个schema标签中定义的表名必须是唯一的。dataNode属性: 定义这个逻辑表所属的dataNode,该属性的值需要和dataNode标签中name属性的值相互对应。 <?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="HEIMADB" checkSQLschema="false" sqlMaxLimit="100"> <table name="product" primaryKey="id" dataNode="dn1,dn2,dn3" rule="mod-long"/> </schema> <dataNode name="dn1" dataHost="localhost1" database="db1" /> <dataNode name="dn2" dataHost="localhost1" database="db2" /> <dataNode name="dn3" dataHost="localhost1" database="db3" /> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- write --> <writeHost host="hostM1" url="localhost:3306" user="root" password="itheima"> <!-- read --> <readHost host="hostS1" url="192.168.203.135:3306" user="root" password="itheima" /> </writeHost> </dataHost> </mycat:schema> 修改主服务器的rule.xml <function name="mod-long" class="io.mycat.route.function.PartitionByMod"> <!-- 数据库的数量 --> <property name="count">3</property> </function>测试
mycat操作 -- 创建product表 CREATE TABLE product( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), price INT ); -- 添加6条数据 INSERT INTO product(id,NAME,price) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,'苹果手机',6999); INSERT INTO product(id,NAME,price) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,'华为手机',5999); INSERT INTO product(id,NAME,price) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,'三星手机',4999); INSERT INTO product(id,NAME,price) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,'小米手机',3999); INSERT INTO product(id,NAME,price) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,'中兴手机',2999); INSERT INTO product(id,NAME,price) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,'OOPO手机',1999); -- 查询product表 SELECT * FROM product; 主服务器操作 -- 在不同数据库中查询product表 SELECT * FROM product; 从服务器操作 -- 在不同数据库中查询product表 SELECT * FROM product;Mycat垂直拆分
修改主服务器的schema <?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="HEIMADB" checkSQLschema="false" sqlMaxLimit="100"> <table name="product" primaryKey="id" dataNode="dn1,dn2,dn3" rule="mod-long"/> <!-- 动物类数据表 --> <table name="dog" primaryKey="id" autoIncrement="true" dataNode="dn4" /> <table name="cat" primaryKey="id" autoIncrement="true" dataNode="dn4" /> <!-- 水果类数据表 --> <table name="apple" primaryKey="id" autoIncrement="true" dataNode="dn5" /> <table name="banana" primaryKey="id" autoIncrement="true" dataNode="dn5" /> </schema> <dataNode name="dn1" dataHost="localhost1" database="db1" /> <dataNode name="dn2" dataHost="localhost1" database="db2" /> <dataNode name="dn3" dataHost="localhost1" database="db3" /> <dataNode name="dn4" dataHost="localhost1" database="db4" /> <dataNode name="dn5" dataHost="localhost1" database="db5" /> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- write --> <writeHost host="hostM1" url="localhost:3306" user="root" password="itheima"> <!-- read --> <readHost host="hostS1" url="192.168.203.135:3306" user="root" password="itheima" /> </writeHost> </dataHost> </mycat:schema>测试
sqlyog连接mycat -- 创建dog表 CREATE TABLE dog( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10) ); -- 添加数据 INSERT INTO dog(id,NAME) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,'哈士奇'); -- 查询dog表 SELECT * FROM dog; -- 创建cat表 CREATE TABLE cat( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10) ); -- 添加数据 INSERT INTO cat(id,NAME) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,'波斯猫'); -- 查询cat表 SELECT * FROM cat; -- 创建apple表 CREATE TABLE apple( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10) ); -- 添加数据 INSERT INTO apple(id,NAME) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,'红富士'); -- 查询apple表 SELECT * FROM apple; -- 创建banana表 CREATE TABLE banana( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10) ); -- 添加数据 INSERT INTO banana(id,NAME) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL,'香蕉'); -- 查询banana表 SELECT * FROM banana; sqlyog连接主服务器 -- 查询dog表 SELECT * FROM dog; -- 查询cat表 SELECT * FROM cat; -- 查询apple表 SELECT * FROM apple; -- 查询banana表 SELECT * FROM banana; sqlyog连接从服务器 -- 查询dog表 SELECT * FROM dog; -- 查询cat表 SELECT * FROM cat; -- 查询apple表 SELECT * FROM apple; -- 查询banana表 SELECT * FROM banana;客户端连接 支持接口:支持的客户端连接,例如 C、Java、PHP 等语言来连接 MySQL 数据库
第一层:网络连接层 连接池:管理、缓冲用户的连接,线程处理等需要缓存的需求。
第二层:核心服务层 管理服务和工具:系统的管理和控制工具,例如备份恢复、复制、集群等。 SQL 接口:接受 SQL 命令,并且返回查询结果。 查询解析器:验证和解析 SQL 命令,例如过滤条件、语法结构等。 查询优化器:在执行查询之前,使用默认的一套优化机制进行优化sql语句。 缓存:如果缓存当中有想查询的数据,则直接将缓存中的数据返回。没有的话再重新查询。
第三层:存储引擎层 插件式存储引擎:管理和操作数据的一种机制,包括(存储数据、如何更新、查询数据等)
第四层:系统文件层 文件系统:配置文件、数据文件、日志文件、错误文件、二进制文件等等的保存。
默认InnDB支持’增删改并发’
默认B+Tree 主键索引 是一定有主键,有就用,没有就唯一约束那一列创建虚拟,都没有就自动增加一列row_id,虚拟不可见 系统从磁盘读取数据到内存以磁盘块为基本单位,同一磁盘块的数据会被一次性读出来,但磁盘数据加载到内存过程会消耗大料的磁盘IO性能,也就是读取磁盘块越多,性能越差,速度越慢
存储引擎中,页是磁盘管理最小单位,默认大小16kb,InnoDB会将表数据+索引存入页中,每个页包含若干个磁盘块,表的数据和索引分布在这些磁盘块中数据量大的表(索引+数据)页很多,非常占用内存,索引不会全部存在内存中,而是存在页的某个的磁盘块内,查询过程中需要把索引和数据的页加载到内存,开始查找。存储的数据结构是否合理,决定了加载页的个数。如果通过优化能降低查询的时候读取页的个数,也就降低了硬盘IO的次数,并最终提高了查询的效率。主键 1.唯一标识一条记录,不能有重复的,不允许为空 2.用来保证数据完整性 3.主键只能有一个
外键 1.表的外键是另一表的主键, 外键可以有重复的, 可以是空值 2.用来和其他表建立联系用的 3. 一个表可以有多个外键 索引 1.该字段没有重复值,但可以有一个空值 2.是提高查询排序的速度 3.一个表可以有多个惟一索引
主键和外键是把多个表组织为一个有效的关系数据库的粘合剂。主键和外键的设计对物理数据库的性能和可用性都有着决定性的影响。
关系数据库依赖于主键—它是数据库物理模式的基石。 主键在物理层面上只有两个用途: 1. 惟一地标识一行。 2. 作为一个可以被外键有效引用的对象。
设计原则
主键应当是对用户没有意义的。如果用户看到了一个表示多对多关系的连接表中的数据,并抱怨它没有什么用处,那就证明它的主键设计地很好。主键应该是单列的,以便提高连接和筛选操作的效率。永远也不要更新主键主键不应包含动态变化的数据,如时间戳、创建时间列、修改时间列等。主键应当有计算机自动生成。索引可以加快查询速度,但索引也是有代价的:索引文件本身要消耗存储空间,同时索引会加重插入、删除和修改记录时的负担,另外,MySQL在运行时也要消耗资源维护索引,因此索引并不是越多越好。 不建议建索引 1.表记录比较少 2.索引的选择性较低