什么是SQL
SQL通用语法
R(Retrieve):查询
-- 查询所有数据库 SHOW DATABASES;
-- 查看mysql数据库的创建格式SHOW CREATE DATABASE mysql; SHOW CREATE DATABASE mysql;
C(Create):创建
-- 创建db1数据库 CREATE DATABASE db1; -- 创建一个已存在的数据库会报错,错误代码:1007 Can't create database 'db1'; database existsCREATE DATABASE db1;
-- 创建数据库db2(判断,如果不存在则创建) CREATE DATABASE IF NOT EXISTS db2;
-- 创建数据库db3、并指定字符集utf8 CREATE DATABASE db3 CHARACTER SET utf8; -- 查看db3数据库的字符集 SHOW CREATE DATABASE db3;
U(Update):修改
-- 修改数据库db4的字符集为utf8 ALTER DATABASE db4 CHARACTER SET utf8;
D(Delete):删除
-- 删除db1数据库 DROP DATABASE db1; -- 删除一个不存在的数据库会报错,错误代码:1008 Can't drop database 'db1'; database doesn't existDROP DATABASE db1;
-- 删除数据库db2,如果存在则删除 zDROP DATABASE IF EXISTS db2;
R(Retrieve):查询
-- 查询库中所有的表 SHOW TABLES;
-- 查询user表结构 DESC user;
C(Create):创建
创建数据表
CREATE TABLE 表名( 列名1 数据类型1, 列名2 数据类型2, .... 列名n 数据类型n);-- 注意:最后一列,不需要加逗号
-- 使用db3数据库 USE db3; -- 创建一个product商品表 CREATE TABLE product( id INT, -- 商品编号 NAME VARCHAR(30), -- 商品名称 price DOUBLE, -- 商品价格 stock INT, -- 商品库存 insert_time DATE -- 上架时间 );
-- 复制product表到product2表 CREATE TABLE product2 LIKE product;
U(Update):修改
-- 修改product2表名为product3 ALTER TABLE product2 RENAME TO product3;
-- 给product3表添加一列color ALTER TABLE product3 ADD color VARCHAR(10);
-- 将color数据类型修改为int ALTER TABLE product3 MODIFY color INT; -- 将color修改为address,数据类型为varchar ALTER TABLE product3 CHANGE color address VARCHAR(30);
-- 删除address列 ALTER TABLE product3 DROP address;
D(Delete):删除
-- 删除product3表 DROP TABLE product3; -- 删除不存在的表,会报错-- 错误代码:1051 Unknown table 'product3'DROP TABLE product3;
-- 删除product3表,如果存在则删除 DROP TABLE IF EXISTS product3;
新增表数据语法
-- 向product表添加一条数据 INSERT INTO product(id,NAME,price,stock,insert_time) VALUES (1,'手机',1999,22,'2099-09-09'); -- 向product表添加指定列数据 INSERT INTO product (id,NAME,price) VALUES (2,'电脑',4999);
-- 默认给全部列添加数据 INSERT INTO product VALUES (3,'电视',2999,18,'2099-06-06');
-- 批量添加数据 INSERT INTO product VALUES (4,'冰箱',999,26,'2099-08-08'),(5,'洗衣机',1999,32,'2099-05-10'); -- 批量添加指定列数据 INSERT INTO product (id,NAME,price) VALUES (6,'微波炉',499),(7,'电磁炉',899);
注意事项
-- 修改手机的价格为3500 UPDATE product SET price=3500 WHERE NAME='手机'; -- 修改电视的价格为1800、库存为36 UPDATE product SET price=1800,stock=36 WHERE NAME='电视'; -- 修改电磁炉的库存为10 UPDATE product SET stock=10 WHERE id=7;
-- 删除product表中的微波炉信息 DELETE FROM product WHERE NAME='微波炉'; -- 删除product表中库存为10的商品信息 DELETE FROM product WHERE stock=10;
select 字段列表from 表名列表where 条件列表group by 分组字段having 分组之后的条件order by 排序limit 分页限定
-- 查询product表所有数据 SELECT * FROM product;
查询部分
-- 查询名称、价格、品牌 SELECT NAME,price,brand FROM product;
-- 查询品牌,去除重复 SELECT DISTINCT brand FROM product;
-- 如果某一列为null,可以进行替换 ifnull(表达式1,表达式2) 表达式1:想替换的列 表达式2:想替换的值 -- 查询商品名称和库存,库存数量在原有基础上加10 SELECT NAME,stock+10 FROM product; -- 查询商品名称和库存,库存数量在原有基础上加10。进行null值判断 SELECT NAME,IFNULL(stock,0)+10 FROM product;
-- 查询商品名称和库存,库存数量在原有基础上加10。进行null值判断。起别名为getSum SELECT NAME,IFNULL(stock,0)+10 AS getsum FROM product;SELECT NAME,IFNULL(stock,0)+10 getsum FROM product;
条件查询
符号 | 功能 |
---|---|
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
= | 等于 |
<> 或 != | 不等于 |
BETWEEN … AND … | 在某个范围之内(都包含) |
IN(…) | 多选一 |
LIKE 占位符 | 模糊查询 _单个任意字符 %多个任意字符 |
IS NULL | 是NULL |
IS NOT NULL | 不是NULL |
AND 或 && | 并且 |
OR 或 || | 或者 |
NOT 或 ! | 非,不是 |
聚合函数
函数名 | 功能 |
---|---|
count(列名) | 统计数量(一般选用不为null的列) |
max(列名) | 最大值 |
min(列名) | 最小值 |
sum(列名) | 求和 |
avg(列名) | 平均值 |
-- 计算product表中总记录条数 SELECT COUNT(*) FROM product; -- 获取最高价格 SELECT MAX(price) FROM product; -- 获取最高价格的商品名称 SELECT NAME,price FROM product WHERE price = (SELECT MAX(price) FROM product); -- 获取最低库存 SELECT MIN(stock) FROM product; -- 获取最低库存的商品名称 SELECT NAME,stock FROM product WHERE stock = (SELECT MIN(stock) FROM product); -- 获取总库存数量 SELECT SUM(stock) FROM product; -- 获取品牌为苹果的总库存数量 SELECT SUM(stock) FROM product WHERE brand='苹果'; -- 获取品牌为小米的平均商品价格 SELECT AVG(price) FROM product WHERE brand='小米';
排序查询
关键词 | 功能 |
---|---|
ORDER BY 列名1 排序方式1,列名2 排序方式2 | 对指定列排序,ASC升序(默认的) DESC降序 |
-- 按照库存升序排序 SELECT * FROM product ORDER BY stock ASC; -- 查询名称中包含手机的商品信息。按照金额降序排序 SELECT * FROM product WHERE NAME LIKE '%手机%' ORDER BY price DESC; -- 按照金额升序排序,如果金额相同,按照库存降序排列 SELECT * FROM product ORDER BY price ASC,stock DESC;
分组查询
-- 按照品牌分组,获取每组商品的总金额 SELECT brand,SUM(price) FROM product GROUP BY brand; -- 对金额大于4000元的商品,按照品牌分组,获取每组商品的总金额 SELECT brand,SUM(price) FROM product WHERE price > 4000 GROUP BY brand;
-- LIMIT 开始索引,查询条数;-- 公式:开始索引 = (当前页码-1) * 每页显示的条数,每页显示2条数据 SELECT * FROM product LIMIT 0,2; -- 第一页 开始索引=(1-1) * 2 SELECT * FROM product LIMIT 2,2; -- 第二页 开始索引=(2-1) * 2 SELECT * FROM product LIMIT 4,2; -- 第三页 开始索引=(3-1) * 2 SELECT * FROM product LIMIT 6,2; -- 第四页 开始索引=(4-1) * 2
约束 | 说明 |
---|---|
PRIMARY KEY | 主键约束 |
PRIMARY KEY AUTO_INCREMENT | 主键、自动增长 |
UNIQUE | 唯一约束 |
NOT NULL | 非空约束 |
FOREIGN KEY | 外键约束 |
FOREIGN KEY ON UPDATE CASCADE | 外键级联更新 |
FOREIGN KEY ON DELETE CASCADE | 外键级联删除 |
-- 标准语法CREATE TABLE 表名( 列名 数据类型 PRIMARY KEY, 列名 数据类型, ...);
-- 删除主键 ALTER TABLE student DROP PRIMARY KEY;
-- 添加主键 ALTER TABLE student MODIFY id INT PRIMARY KEY;
-- 标准语法CREATE TABLE 表名( 列名 数据类型 PRIMARY KEY AUTO_INCREMENT, 列名 数据类型, ...);
-- 标准语法ALTER TABLE 表名 MODIFY 列名 数据类型; -- 删除自动增长 ALTER TABLE student2 MODIFY id INT;
-- 标准语法ALTER TABLE 表名 MODIFY 列名 数据类型 AUTO_INCREMENT; -- 添加自动增长 ALTER TABLE student2 MODIFY id INT AUTO_INCREMENT;
-- 标准语法CREATE TABLE 表名( 列名 数据类型 UNIQUE, 列名 数据类型, ...);-
-- 标准语法ALTER TABLE 表名 DROP INDEX 列名;-- 删除唯一约束 ALTER TABLE student3 DROP INDEX tel;
-- 标准语法ALTER TABLE 表名 MODIFY 列名 数据类型 UNIQUE;-- 添加唯一约束 ALTER TABLE student3 MODIFY tel VARCHAR(20) UNIQUE;
-- 标准语法CREATE TABLE 表名( 列名 数据类型 NOT NULL, 列名 数据类型, ...);
-- 标准语法ALTER TABLE 表名 MODIFY 列名 数据类型;-- 删除非空约束 ALTER TABLE student4 MODIFY NAME VARCHAR(20);
建表后单独添加非空约束
-- 标准语法ALTER TABLE 表名 MODIFY 列名 数据类型 NOT NULL;-- 添加非空约束 ALTER TABLE student4 MODIFY NAME VARCHAR(20) NOT NULL;
外键约束概念
让表和表之间产生关系,一张表的变得将关联另外一张表,从而保证数据的准确性!
外键约束格式
CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主表主键列名)
删除外键约束
-- 删除外键 ALTER TABLE orderlist DROP FOREIGN KEY ou_fk1;
建表后添加外键约束
-- 标准语法 ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主键列名); -- 添加外键约束 ALTER TABLE orderlist ADD CONSTRAINT ou_fk1 FOREIGN KEY (uid) REFERENCES USER(id);
分析
实现原则
图解
有两张表,获取这两个表的所有组合情况
要完成多表查询,需要消除这些没有用的数据
多表查询格式
笛卡尔积查询
-- 标准语法SELECT 列名 FROM 表名1,表名2,...; -- 查询user表和orderlist表 SELECT * FROM USER,orderlist;
-- 查询用户信息和对应的订单信息 SELECT * FROM USER INNER JOIN orderlist ON user.id=orderlist.uid; SELECT * FROM USER JOIN orderlist ON user.id=orderlist.uid;
-- 查询用户姓名,年龄。和订单编号 SELECT u.`name`,-- 姓名 u.`age`, -- 年龄 o.`number` -- 订单编号 FROM USER u, -- 用户表 orderlist o -- 订单表 WHERE u.`id`=o.`uid`;
左外连接
-- 查询所有用户信息,以及用户对应的订单信息 SELECT u.`name`, -- 姓名 u.`age`, -- 年龄 o.`number` -- 订单编号 FROM USER u -- 用户表 LEFT OUTER JOIN orderlist o -- 订单表 ON u.`id`=o.`uid`;
右外连接
-- 查询所有订单信息,以及订单所属的用户信息 SELECT u.`name`, -- 姓名 u.`age`, -- 年龄 o.`number` -- 订单编号 FROM USER u -- 用户表 RIGHT OUTER JOIN orderlist o -- 订单表 ON u.`id`=o.`uid`;
子查询介绍
子查询-结果是单行单列的
-- 查询年龄最高的用户姓名 SELECT MAX(age) FROM USER; -- 查询出最高年龄 SELECT NAME,age FROM USER WHERE age=26; -- 根据查询出来的最高年龄,查询姓名和年龄 SELECT NAME,age FROM USER WHERE age = (SELECT MAX(age) FROM USER);
子查询-结果是多行单列的
-- 查询张三和李四的订单信息 SELECT id FROM USER WHERE NAME='张三' OR NAME='李四'; -- 查询张三和李四用户的id SELECT number,uid FROM orderlist WHERE uid=1 OR uid=2; -- 根据id查询订单 SELECT number,uid FROM orderlist WHERE uid IN (SELECT id FROM USER WHERE NAME='张三' OR NAME='李四');
子查询-结果是多行多列的
-- 查询订单表中id大于4的订单信息和所属用户信息 SELECT * FROM USER u,(SELECT * FROM orderlist WHERE id>4) o WHERE u.id=o.uid;
-- 标准语法CREATE VIEW 视图名称 [(列名列表)] AS 查询语句;
-- 普通多表查询,查询城市和所属国家 SELECT t1.*, t2.country_nameFROM city t1, country t2WHERE t1.cid = t2.id; -- 经常需要查询这样的数据,就可以创建一个视图
-- 创建一个视图。将查询出来的结果保存到这张虚拟表中 CREATEVIEW city_countryAS SELECT t1.*,t2.country_name FROM city t1,country t2 WHERE t1.cid=t2.id;
-- 创建一个视图,指定列名。将查询出来的结果保存到这张虚拟表中 CREATEVIEW city_country2 (city_id,city_name,cid,country_name) AS SELECT t1.*,t2.country_name FROM city t1,country t2 WHERE t1.cid=t2.id;
-- 标准语法SELECT * FROM 视图名称;
-- 查询视图。查询这张虚拟表,就等效于查询城市和所属国家 SELECT * FROM city_country; -- 查询指定列名的视图 SELECT * FROM city_country2;-- 查询所有数据表,视图也会查询出来SHOW TABLES;
-- 标准语法SHOW CREATE VIEW 视图名称;
SHOW CREATE VIEW city_country;
-- 修改视图表中的城市名称北京为北京市 UPDATE city_country SET city_name='北京市' WHERE city_name='北京'; -- 查询视图 SELECT * FROM city_country; -- 查询city表,北京也修改为了北京市 SELECT * FROM city; -- 注意:视图表数据修改,会自动修改源表中的数据
-- 查询视图2 SELECT * FROM city_country2; -- 修改视图2的列名city_id为id ALTERVIEW city_country2 (id,city_name,cid,country_name)AS SELECT t1.*,t2.country_name FROM city t1,country t2 WHERE t1.cid=t2.id;
-- 删除视图 DROP VIEW city_country; -- 删除视图2,如果存在则删除 DROP VIEW IF EXISTS city_country2;
-- 张三给李四转账500元 -- 1.张三账户-500 UPDATE account SET money=money-500 WHERE NAME='张三'; -- 2.李四账户+500出错了... UPDATE account SET money=money+500 WHERE NAME='李四'; -- 该场景下,这两条sql语句要么同时成功,要么同时失败。就需要被事务所管理!
-- 标准语法 START TRANSACTION;
-- 标准语法 ROLLBACK;
-- 标准语法 COMMIT;
-- 开启事务 START TRANSACTION; -- 张三给李四转账500元 -- 1.张三账户-500 UPDATE account SET money=money-500 WHERE NAME='张三'; -- 2.李四账户+500-- 出错了... UPDATE account SET money=money+500 WHERE NAME='李四'; -- 回滚事务(出现问题) ROLLBACK; -- 提交事务(没出现问题) COMMIT;
提交方式
修改提交方式
-- 标准语法 SELECT @@AUTOCOMMIT; -- 1代表自动提交 0代表手动提交
-- 标准语法 SET @@AUTOCOMMIT=数字; -- 修改为手动提交 SET @@AUTOCOMMIT=0; -- 查看提交方式 SELECT @@AUTOCOMMIT;
1 | 读未提交 | read uncommitted |
---|---|---|
2 | 读已提交 | read committed |
3 | 可重复读 | repeatable read |
4 | 串行化 | serializable |
问题 | 现象 |
---|---|
脏读 | 是指在一个事务处理过程中读取了另一个未提交的事务中的数据 , 导致两次查询结果不一致 |
不可重复读 | 是指在一个事务处理过程中读取了另一个事务中修改并已提交的数据, 导致两次查询结果不一致 |
幻读 | select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入。或不存在执行delete删除,却发现删除成功 |
-- 标准语法 SELECT @@TX_ISOLATION;
隔离级别 | 名称 | 出现脏读 | 出现不可重复读 | 出现幻读 | 数据库默认隔离级别 | |
---|---|---|---|---|---|---|
1 | read uncommitted | 读未提交 | 是 | 是 | 是 | |
2 | read committed | 读已提交 | 否 | 是 | 是 | Oracle / SQL Server |
3 | repeatable read | 可重复读 | 否 | 否 | 是 | MySQL |
4 | **serializable ** | 串行化 | 否 | 否 | 否 |
注意:隔离级别从小到大安全性越来越高,但是效率越来越低 , 所以不建议使用READ UNCOMMITTED 和 SERIALIZABLE 隔离级别.
体系结构的概念
MySQL的体系结构
体系结构详解
引擎的概念
MySQL存储引擎的概念
MySQL支持的存储引擎
特性 | MyISAM | InnoDB | MEMORY |
---|---|---|---|
存储限制 | 有(平台对文件系统大小的限制) | 64TB | 有(平台的内存限制) |
事务安全 | 不支持 | 支持 | 不支持 |
锁机制 | 表锁 | 表锁/行锁 | 表锁 |
B+Tree索引 | 支持 | 支持 | 支持 |
哈希索引 | 不支持 | 不支持 | 支持 |
全文索引 | 支持 | 支持 | 不支持 |
集群索引 | 不支持 | 支持 | 不支持 |
数据索引 | 不支持 | 支持 | 支持 |
数据缓存 | 不支持 | 支持 | N/A |
索引缓存 | 支持 | 支持 | N/A |
数据可压缩 | 支持 | 不支持 | 不支持 |
空间使用 | 低 | 高 | N/A |
内存使用 | 低 | 高 | 中等 |
批量插入速度 | 高 | 低 | 高 |
外键 | 不支持 | 支持 | 不支持 |
查找顺序:
模拟查找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上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。因此可以对B+Tree进行两种查找运算:
实际情况中每个节点可能不能填充满,因此在数据库中,B+Tree的高度一般都在2~4层。MySQL的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要1~3次磁盘I/O操作。
对查询频次较高,且数据量比较大的表建立索引。
使用唯一索引,区分度越高,使用索引的效率越高。
索引字段的选择,最佳候选列应当从where子句的条件中提取,如果where子句中的组合比较多,那么应当挑选最常用、过滤效果最好的列的组合。
根据查询条件,基于最左匹配原则,构建索引;
使用短索引,索引创建之后也是使用硬盘来存储的,因此提升索引访问的I/O效率,也可以提升总体的访问效率。但是实际我们必须要根据某一列的值构建索引,而这一列的值有很大时,我们会通过取前缀的方式,构建‘前缀索引’,
计算前缀大小的方式(值最少大于0.9):例
SELECT COUNT(DISTINCT SUBSTRING(NAME,1,8))/COUNT(1) FROM product;
一张表的索引不宜过多,不超过5个;索引是一个存储数据的树,如果一张表的索引过多,回到这磁盘控件占用过大;索引上的数据是有序的,如果涉及增删改操作,索引树上的数据要重新维护,如果索引过多,会带来增删改性能的影响
尽可能减少回表操作,可以将要查询的内容也做到索引树上 – ‘覆盖索引’(索引列不仅来自于查询条件,还可能来自于查询的内容)
在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由于自身架构的特点,在不同的存储引擎中,都设计了面对特定场景的锁定机制,所以引擎的差别,导致锁机制也是有很大差别的。
存储引擎 | 表级锁 | 行级锁 | 页级锁 |
---|---|---|---|
MyISAM | 支持 | 不支持 | 不支持 |
InnoDB | 支持 | 支持 | 不支持 |
MEMORY | 支持 | 不支持 | 不支持 |
BDB | 支持 | 不支持 | 支持 |
悲观锁的概念
乐观锁的概念
悲观锁和乐观锁使用前提
乐观锁的实现方式
版本号
时间戳
表锁和行锁
InnoDB锁优化建议
尽量通过带索引的列来完成数据查询,从而避免InnoDB无法加行锁而升级为表锁。
合理设计索引,索引要尽可能准确,尽可能的缩小锁定范围,避免造成不必要的锁定。
尽可能减少基于范围的数据检索过滤条件。
尽量控制事务的大小,减少锁定的资源量和锁定时间长度。
在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率。
对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁的产生。
我们来说个例子,大海捞针和一个水瓶里捞针,毋庸置疑水瓶里一定能更快找到针,因为它需要检索的范围更小。数据库集群也是如此原理,我们可以将一个数据量为300G的数据库数据平均拆分成3部分,每个数据库中只存储100G数据,此时用户搜索,先经过我们中间代理层,中间代理层同时发出3个请求执行查询,比如第1台返回100条数据,耗时3秒,第2台返回200条数据,耗时3秒,第3台返回500条数据,耗时3秒,此时中间件只需要在800条记录中进行筛选,即可检索出用户要的结果,此时耗时其实一共只有3秒,因为每台机器做运算的时候,都是同时执行。如果我们此时直接在300G的数据库查询,耗时10秒,那使用中间件进行集群的效率就非常明显
MyCat的实现流程和这个流程大致相似。MyCat自身不存储数据,但用户每次链接数据库的时候,直接连接MyCat即可.所以我们MyCat自身其实就是个逻辑数据库,它自身还有表结构,表结构叫逻辑表。
主从复制的概念
分库分表的概念