MySQL总结
欢迎光临我的博客[http://poetize.cn],前端使用Vue2,聊天室使用Vue3,后台使用Spring Boot
Mysql
中文乱码 修改字符集
vim /etc/my.cnf
在最后加入中文字符集配置:character_set_server=utf8
重启:systemctl restart mysqld
修改已存在数据库的字符集:alter database saradb character set 'utf8';
修改已存在表的字符集:alter table user convert to character set 'utf8';
用户与权限管理
创造用户:create user ld identified by 'aaa';
查看当前用户权限:show grants;
设置权限:
grant select,insert,delete,drop on saradb.* to ld@localhost;
grant all privileges on *.* to ld@'%' identified by 'aaa';
修改当前用户的密码:set password=password('aaa');
修改某个用户的密码:update mysql.user set password=password('aaa') where user='ld';
修改用户名:update mysql.user set user='ld' where user='sara';
删除用户:drop user ld;
关闭数据库服务的防火墙:service iptables stop
mysql 2058错误:
GRANT ALL ON *.* TO 'root'@'%';
flush privileges;
ALTER USER 'root'@'%' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER;
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'aaa';
flush privileges;
Docker 安装 Mysql
docker run -di --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=aaa mysql
docker exec -it mysql bash:伪终端
ps -ef | grep -i Mysql:查看Mysql进程
mkdir -p /data/mariadb/data
docker run -di --name mariadb -p 3306:3306 -e MYSQL_ROOT_PASSWORD=aaa -v /data/mariadb/data:/var/lib/mysql mariadb
sql检验原则
group by使用原则:select 后面只能放函数和group by后的字段
show variables like 'sql_mode';
select @@sql_mode;
改变全局sql_mode,对于新建的数据库有效:
set @@sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
已存在的数据库,需要在对应的数据下执行:
set sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
mysql逻辑架构
1. 程序访问与连接池沟通
2. 缓存,缓冲查询
3. SQL接口分析sql语句
4. 解析器复杂sql语句解析
5. 优化器优化,生成执行计划
6. 存储引擎按计划分类型执行
7. 存入缓存
8. 返回结果
查看sql执行周期
启用查询缓存:
/etc/my.cnf配置文件新增一行:query_cache_type=1
开启执行周期:
show variables like '%profiling%';
set profiling=1;
show profiles;
sql语句
select distinct
select_list
from
left_table join_type join right_table on join_condition
where
where_condition
group by
group_by_list
having
having_condition
limit
limit_number
存储引擎
MyISAM:不支持外键与事务,表锁,只缓存索引,不缓存真实数据(节省资源)
InnoDB:支持外键与事务,行锁(适合高并发),不仅缓存索引,还缓存真实数据
查看mysql当前默认的存储引擎:show variables like '%storage_engine%';
sql性能下降原因
数据过多:分库分表
join关联太多表:sql优化
没有充分利用索引:建立索引(效果最好)
服务器调优:调整my.cnf
join
from tableA inner join tableB on join_condition:内连接(交集)
from tableA left join tableB on join_condition:左外连接(A表全集)
from tableA left join tableB on join_condition where tableB.id is null:左外连接(A表独有)
union:联合查询,自动去重(影响性能),必须保证字段数与顺序一致(select a.*,b.*)
union all:联合查询,不去重,必须保证字段数与顺序一致(select a.*,b.*)
USE mydb;
CREATE TABLE `t_dept` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`deptName` VARCHAR(30) DEFAULT NULL,
`address` VARCHAR(40) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `t_emp` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) DEFAULT NULL,
`age` INT(3) DEFAULT NULL,
`deptId` INT(11) DEFAULT NULL,
empno INT NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_dept_id` (`deptId`)
#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `t_dept` (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO t_dept(deptName,address) VALUES('华山','华山');
INSERT INTO t_dept(deptName,address) VALUES('丐帮','洛阳');
INSERT INTO t_dept(deptName,address) VALUES('峨眉','峨眉山');
INSERT INTO t_dept(deptName,address) VALUES('武当','武当山');
INSERT INTO t_dept(deptName,address) VALUES('明教','光明顶');
INSERT INTO t_dept(deptName,address) VALUES('少林','少林寺');
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('风清扬',90,1,100001);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('岳不群',50,1,100002);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('令狐冲',24,1,100003);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('洪七公',70,2,100004);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('乔峰',35,2,100005);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('灭绝师太',70,3,100006);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('周芷若',20,3,100007);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('张三丰',100,4,100008);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('张无忌',25,5,100009);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('韦小宝',18,NULL,100010);
七种join:
1. 所有有门派的人员信息( A、B两表共有)
select * from t_emp a inner join t_dept b on a.deptId = b.id;
2. 列出所有用户,并显示其机构信息(A的全集)
select * from t_emp a left join t_dept b on a.deptId = b.id;
3. 列出所有门派(B的全集)
select * from t_dept b
4. 所有不入门派的人员(A的独有)
select * from t_emp a left join t_dept b on a.deptId = b.id where b.id is null;
5. 所有没人入的门派(B的独有)
select * from t_dept b left join t_emp a on a.deptId = b.id where a.deptId is null;
6. 列出所有人员和机构的对照关系(AB全有)
#MySQL Full Join的实现 因为MySQL不支持FULL JOIN,下面是替代方法
#left join + union(可去除重复数据)+ right join
SELECT * FROM t_emp A LEFT JOIN t_dept B ON A.deptId = B.id
UNION
SELECT * FROM t_emp A RIGHT JOIN t_dept B ON A.deptId = B.id
7. 列出所有没入派的人员和没人入的门派(A的独有+B的独有)
SELECT * FROM t_emp A LEFT JOIN t_dept B ON A.deptId = B.id WHERE B.`id` IS NULL
UNION
SELECT * FROM t_emp A RIGHT JOIN t_dept B ON A.deptId = B.id WHERE A.`deptId` IS NULL;
索引
优势:查询快,排序快
缺点:更新慢,占用空间
索引结构:平衡二叉树(时间复杂度logN)
BTree
B+Tree(内存占用率低,磁盘读写代价更低,查询效率更加稳定)
数组:查找N,插入1
有序数组(二分查找法):查找logN,插入N
链表:查找N,插入1
有序链表:查找N,插入N
二叉树(一般情况):查找logN,插入logN
二叉树(最坏情况):查找N,插入N
平衡树:查找logN,插入logN
哈希表:查找1,插入1
mysql索引分类:
单值索引key:即一个索引只包含单个列,一个表可以有多个单列索引
唯一索引unique:索引列的值必须唯一,但允许有空值
主键索引primary key:设定为主键后数据库会自动建立索引,innodb为聚簇索引
复合索引key (key1,key2):即一个索引包含多个列
创建:CREATE [UNIQUE] INDEX [indexName] ON table_name(column);
删除:DROP INDEX [indexName] ON table_name;
ALTER TABLE table_name ADD PRIMARY KEY (column_list): 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。
ALTER TABLE table_name ADD UNIQUE index_name (column_list): 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。
ALTER TABLE table_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现多次。
ALTER TABLE table_name ADD FULLTEXT index_name (column_list):该语句指定了索引为 FULLTEXT ,用于全文索引。
需要创建索引的情况:
频繁作为查询条件的字段
查询中与其他表关联的字段
排序的字段
统计的字段
分组的字段
Explain执行计划
id:每个id号码,表示一次独立的查询。一个sql的查询次数越少越好。
type显示的是访问类型,是较为重要的一个指标,结果值从最好到最坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
system > const > eq_ref > ref > range > index > ALL
eq_ref:唯一性索引扫描,常用于主键或唯一索引扫描
ref:非唯一性索引扫描
range:范围索引扫描,一般在where语句中出现between,<,>,in等的查询
index:覆盖索引扫描
all:遍历全表
index_merge:组合索引扫描,通常出现在有or的关键字的sql中
Using filesort:order by未用上索引,文件排序,性能低
Using temporary:group by未用上索引,文件排序,包含filesort,性能极低
USing join buffer:两个表关联,关联字段一定要建立索引
单表索引优化
最佳左前缀法则:如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列
过滤性最好的字段在索引字段顺序中,位置越靠前越好。
索引失效:
1. 在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
2. 范围查询索引右边的索引失效,存储引擎不能使用索引中范围条件右边的列。可能出现范围查询的字段应该放在复合索引中靠后的位置
3. <>不等于,is not索引失效
4. like '%abc'索引失效('abc%'不会失效)
关联,子查询索引优化
驱动表:前面的表,无法避免关联查询
被驱动表:后面的表,关联字段需要建立索引
1. 保证被驱动表的join字段已经被索引
2. left join时,选择小表作为驱动表,大表作为被驱动表。
3. inner join时,mysql会自动把具有索引的表作为被驱动表,如果没有索引,则大结果集的表选为被驱动表。
4. 子查询尽量不要放在被驱动表,有可能使用不到索引。
5. 能够直接多表关联的尽量直接关联,不用子查询。
查询员工姓名与员工ceo姓名
快(直接关联):
EXPLAIN SELECT SQL_NO_CACHE a.`name`,c.`name` ceo
FROM emp a
LEFT JOIN dept b ON a.`deptId`=b.`id`
LEFT JOIN emp c ON b.`ceo`=c.`id`;
慢(子查询):
EXPLAIN SELECT SQL_NO_CACHE a.`name`,(SELECT c.name FROM emp c WHERE c.id=b.`ceo`) ceo
FROM emp a LEFT JOIN dept b ON a.`deptId`=b.`id`;
6. 尽量不要使用not in或者not exists,用left outer join on xxx is null 替代
取所有不为掌门人的员工,按年龄分组 ,每个年龄段多少人
SELECT SQL_NO_CACHE age,count(*)
FROM emp a
WHERE id NOT IN(SELECT ceo FROM dept WHERE ceo IS NOT NULL)
group by age
having count(*)<10000
SELECT SQL_NO_CACHE age,count(*)
FROM emp a LEFT OUTER JOIN dept b ON a.id =b.ceo
WHERE b.ceo IS NULL
group by age
having count(*)<10000
#1. 列出自己ceo比自己年龄小的人员
EXPLAIN SELECT SQL_NO_CACHE a.`name`,a.`age`,c.`name` ceo,c.`age` ceoage
FROM emp a
LEFT JOIN dept b ON a.`deptId`=b.`id`
LEFT JOIN emp c ON b.`ceo`=c.`id`
WHERE a.`age`>c.`age`;
#2. 列出所有年龄低于自己门派平均年龄的成员
EXPLAIN SELECT SQL_NO_CACHE a.`name`,a.`age`,b.avgage
FROM emp a
INNER JOIN
(SELECT deptId,AVG(age) avgage
FROM emp
WHERE deptId IS NOT NULL
GROUP BY deptId) b
ON a.`deptId`=b.`deptId`
WHERE a.`age`<b.avgage;
CREATE INDEX idx_deptId_age ON emp(deptId,age);
#3. 列出至少有两个年龄大于40的成员的门派
EXPLAIN SELECT SQL_NO_CACHE b.`deptName`,COUNT(*)
FROM emp a
INNER JOIN dept b ON a.`deptId`=b.`id`
WHERE a.`age`>40
GROUP BY a.`deptId`
HAVING COUNT(*)>1;
CREATE INDEX idx_deptId_age ON emp(deptId,age);
#4. 显示每个门派年龄最大的人
EXPLAIN SELECT SQL_NO_CACHE b.`name`,b.`age`
FROM emp b
INNER JOIN
(SELECT a.`deptId`,MAX(a.`age`)maxage
FROM emp a
WHERE a.`deptId` IS NOT NULL
GROUP BY a.`deptId`)aa
ON b.`deptId`=aa.deptId AND b.`age`=aa.maxage;
排序分组优化
order by不过滤不索引,要想用上索引必须有过滤条件
order by字段顺序必须与索引顺序一致
order by要么都是升序,要么都是降序
当范围条件和group by或者order by的字段出现二选一时,优先观察条件字段的过滤数量,
如果过滤的数据足够多,而需要排序的数据并不多时,优先把索引放在范围字段上
双路排序:从磁盘取排序字段,在buffer进行排序,再从磁盘取其他字段。取一批数据,要对磁盘进行了两次IO扫描,效率低
单路排序:从磁盘读取查询需要的所有列,按照order by列在buffer对它们进行排序,然后扫描排序后的列表进行输出(效率高)
单路排序缺点:
取出的数据的总大小超出了sort_buffer的容量,
导致每次只能取sort_buffer容量大小的数据,进行排序(创建tmp文件,多路合并),
排完再取取sort_buffer容量大小,再排...从而多次I/O。
单路排序优化:增大sort_buffer_size参数的设置,增大max_length_for_sort_data参数的设置,减少select后面的查询的字段。
group by使用索引的原则几乎跟order by一致,唯一区别是group by即使没有过滤条件用到索引,也可以直接使用索引。
清除索引
DELIMITER $$
CREATE PROCEDURE `proc_drop_index`(dbname VARCHAR(200),tablename VARCHAR(200))
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE ct INT DEFAULT 0;
DECLARE _index VARCHAR(200) DEFAULT '';
DECLARE _cur CURSOR FOR SELECT index_name FROM information_schema.STATISTICS WHERE table_schema=dbname AND table_name=tablename AND seq_in_index=1 AND index_name <>'PRIMARY';
DECLARE CONTINUE HANDLER FOR NOT FOUND set done=2;
OPEN _cur;
FETCH _cur INTO _index;
WHILE _index<>'' DO
SET @str = CONCAT("drop index ",_index," on ",tablename );
PREPARE sql_str FROM @str;
EXECUTE sql_str;
DEALLOCATE PREPARE sql_str;
SET _index='';
FETCH _cur INTO _index;
END WHILE;
CLOSE _cur;
END$$
CALL proc_drop_index("dbname","tablename");
慢查询日志
运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为10,意思是运行10秒以上的语句。
查看:SHOW VARIABLES LIKE '%slow_query_log%';
开启:set global slow_query_log=1;
永久开启:
将如下两行配置进my.cnf文件
slow_query_log =1
slow_query_log_file=/var/lib/mysql/sara-slow.log
时间查看:SHOW VARIABLES LIKE 'long_query_time%';
时间修改:set global long_query_time=1;
日志分析工具:mysqldumpslow
-s: 是表示按照何种方式排序
r: 返回记录
c: 访问次数
t: 查询时间
-t:即为返回前面多少条的数据;
-g:后边搭配一个正则匹配模式,大小写不敏感的
得到返回记录集最多的10个SQL
mysqldumpslow -s r -t 10 /var/lib/mysql/sara-slow.log
得到访问次数最多的10个SQL
mysqldumpslow -s c -t 10 /var/lib/mysql/sara-slow.log
得到按照时间排序的前10条里面含有左连接的查询语句
mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/sara-slow.log
另外建议在使用这些命令时结合 | 和 more 使用 ,否则有可能出现爆屏情况
mysqldumpslow -s r -t 10 /var/lib/mysql/sara-slow.log | more
视图
创建:
create view view_name as
select * from emp;
更新:
CREATE OR REPLACE VIEW view_name AS
select * from emp;
查询:
select * from view_name
将一段查询sql封装为一个虚拟的表,封装复杂sql语句,提高复用性
主从复制(具有延时问题,必须主从复制配置搭配好才能创造数据库)
1. 在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力(主库写,从库读,降压)
2. 在从主服务器进行备份,避免备份期间影响主服务器服务(确保数据安全)
3. 当主服务器出现问题时,可以切换到从服务器(提升性能)
MySQL复制过程分成三步:
1 master将改变记录到二进制日志(binary log)。这些记录过程叫做二进制日志事件,binary log events
2 slave将master的binary log events拷贝到它的中继日志(relay log)
3 slave重做中继日志中的事件,将改变应用到自己的数据库中。 MySQL复制是异步的且串行化的
配置:主从配置都在my.cnf配置文件的[mysqld]结点下
主机:
主服务器唯一ID:server-id=1
二进制日志储存路径:log-bin=自己本地的路径/data/mysqlbinlog
设置不要复制的数据库:binlog-ignore-db=mysql
设置需要复制的数据库:binlog-do-db=需要复制的主数据库名字
主机上建立帐户并授权slave:GRANT REPLICATION SLAVE ON *.* TO 'sara'@'%' IDENTIFIED BY 'aaa';
查询master的状态:show master status;
从机:
从服务器唯一ID:server-id=2
开启中继日志:relay-log=mysql-relay
从机上配置需要复制的主机:CHANGE MASTER TO MASTER_HOST='主机IP',MASTER_USER='sara',MASTER_PASSWORD='aaa',MASTER_LOG_FILE='binlog名字',MASTER_LOG_POS=Position数字;
启动从服务器复制功能:start slave;
查询slave的状态:show slave status\G;
停止从服务复制功能:stop slave;
重新配置从服务器:stop slave;reset master;
关闭防火墙:systemctl stop firewalld
Mycat(读写分离,数据分片,多数据源整合)
读写分离,负载均衡
Mycat的原理中最重要的一个动词是“拦截”,
它拦截了用户发送过来的 SQL 语句,
首先对 SQL 语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,
然后将此 SQL 发往后端的真实数据库,
并将返回的结果做适当的处理,最终再返回给用户
schema.xml:定义逻辑库,表、分片节点等内容
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema>
<dataNode name="dn1" dataHost="host1" database="saradb"/>
<dataHost name="host1" maxCon="1000" minCon="10" balance="3"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="192.168.111.222:3306" user="root" password="aaa">
<readHost host="hostS1" url="192.168.111.223:3306" user="root" password="aaa"/>
</writeHost>
</dataHost>
</mycat:schema>
负载均衡类型,目前的取值有4种:
1. balance="0",不开启读写分离机制,所有读操作都发送到当前可用的writeHost上。
2. balance="1",全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与M2互为主备),正常情况下,M2,S1,S2 都参与select语句的负载均衡。
3. balance="2",所有读操作都随机的在writeHost、readhost上分发。
4. balance="3",所有读请求随机的分发到readhost执行,writerHost不负担读压力
rule.xml:定义分片规则
server.xml:定义用户以及系统相关变量,如端口等
<user name="root">
<property name="password">654321</property>
<property name="schemas">TESTDB</property>
</user>
启动:
控制台启动:去mycat/bin目录下mycat console
后台启动:去mycat/bin目录下mycat start
登录:
管理:mysql -uroot -paaa -P9066 -h192.168.111.223
数据:mysql -uroot -paaa -P8066 -h192.168.111.223
分库
分库:将同一个库(lddb)的表(其他表,customer)放在不同主机的数据库,减轻数据库压力
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
<!-- 分库:customer表将会创建在host2主机上,其他表将会创建在host1主机上 -->
<!-- 两个主机都需要手动创建数据库 -->
<table name="customer" dataNode="dn2"></table>
</schema>
<dataNode name="dn1" dataHost="host1" database="lddb_1"/>
<!-- 分库 -->
<dataNode name="dn2" dataHost="host2" database="lddb_2"/>
<dataHost name="host1" maxCon="1000" minCon="10" balance="3"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="192.168.111.222:3306" user="root" password="aaa">
<readHost host="hostS1" url="192.168.111.223:3306" user="root" password="aaa"/>
</writeHost>
</dataHost>
<!-- 分库 -->
<dataHost name="host2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostm2" url="192.168.111.223:3306" user="root" password="aaa"></writeHost>
</dataHost>
</mycat:schema>
分表
分表:将同一个表(order)的数据根据表的字段(customer_id)通过函数运算放入不同主机的数据库,减轻数据库压力
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
<table name="order" dataNode="dn1,dn2" rule="mod_rule"></table>
</schema>
</mycat:schema>
<tableRule name="mod_rule">
<rule>
<columns>customer_id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">2</property>
</function>
跨库join
配置ER表:为了相关联的表的行尽量分在一个库下
<table name="order" dataNode="dn1,dn2" rule="mod_rule" >
<childTable name="order_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
</table>
全局表:设定为全局的表,会直接复制给每个数据库一份,所有写操作也会同步给多个库。
<table name="dict_order_type" dataNode="dn1,dn2" type="global"></table>
设置全局序列
数据分表,如果自增主键会造成主键重复,需要设置全局序列(数据库方式)
利用数据库一个表来进行计数累加。
在数据库中建立一张表,存放sequence名称(name),sequence当前值(current_value),步长(increment int类型每次读取多少个sequence)
mycat会预加载一部分号段到mycat的内存中,这样大部分读写序列都是在内存中完成的。
如果内存中的号段用完了,mycat会再向数据库要一次。
创建MYCAT_SEQUENCE表(dn1数据库中)
CREATE TABLE MYCAT_SEQUENCE (
NAME VARCHAR(50) NOT NULL,
current_value INT NOT NULL,
increment INT NOT NULL DEFAULT 100,
PRIMARY KEY(NAME)
) ENGINE=INNODB;
#插入了一个名为ORDER的SEQUENCE,当前值为400000,步长为100。
INSERT INTO MYCAT_SEQUENCE(NAME,current_value,increment) VALUES ('ORDER', 400000, 100);
SELECT * FROM MYCAT_SEQUENCE
TRUNCATE TABLE MYCAT_SEQUENCE(直接删除数据,不带回滚)
创建存储函数:必须在同一个数据库中创建(dn1数据库中)
DELIMITER $$
CREATE FUNCTION mycat_seq_currval(
seq_name VARCHAR(50)
) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval="-999999999,null";
SELECT CONCAT(CAST(current_value AS CHAR),",",CAST(increment AS CHAR)) INTO retval
FROM MYCAT_SEQUENCE WHERE NAME = seq_name;
RETURN retval;
END $$
DELIMITER;
DELIMITER $$
CREATE FUNCTION mycat_seq_setval(
seq_name VARCHAR(50),
VALUE INTEGER
) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE SET current_value = VALUE WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$
DELIMITER;
DELIMITER $$
CREATE FUNCTION mycat_seq_nextval(
seq_name VARCHAR(50)
) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$
DELIMITER;
修改mycat的sequence_db_conf.properties配置(配置数据库的节点,即全局序列储存在哪个数据库):
ORDER=dn1:意思是ORDER(必须大写)这个序列储存在dn1数据库节点上
修改mycat的server.xml配置(将全局序列改为数据库方式):
<property name="sequnceHandlerType">1</property>
插入语句:
insert into order(id,amount,customer_id,order_type) values(next value for MYCATSEQ_ORDER,1000,101,102);