SQL优化

mysql系统架构

逻辑模块组成

mysql由两层架构组成
1.第一层sqllayer处理底层数据之前所有工作,包括权限判断,sql解析,执行计划优化
2.第二层就是存储引擎层,我们通常叫做Storage EngineLayer,也就是底层数据存取操作实现部分,由多种存储引擎共同组成

image.png

各模块工作配合

image.png

常用引擎介绍

MyISAM

MyISAM 存储引擎的表在数据库中,每一个表都被存放为三个以表名命名的物理文件。首先肯定会有任何存储引擎都不可缺少的存放表结构定义信息的.frm 文件,另外还有.MYD和.MYI 文件,分别存放了表的数据(.MYD)和索引数据(.MYI)。每个表都有且仅有这样三个文件做为 MyISAM 存储类型的表的存储,也就是说不管这个表有多少个索引,都是存放在同一个.MYI 文件中。

Innodb

在物理存储方面,Innodb 存储引擎也和 MyISAM 不太一样,虽然也有.frm 文件来存放表结构定义相关的元数据,但是表数据和索引数据是存放在一起的。

对比

image.png

索引

SELECT * FROM my_table WHERE col2 = '77' 可以从表“my_table”中获得“col2”为“77”的数据记录。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。

索引类型分类

B+tree
使用平衡树实现索引,是mysql中使用最多的索引类型
;在innodb中,存在两种索引类型
《第一种是主键索引(primary key),索引内容中直接保存数据的地址》
《第二种是其他索引,在索引内容中保存的是指向主键索引的引用;》
所以在使用innodb的时候,要尽量的使用主键索引,速度非常快;
hash
把索引的值做hash运算,并存放到hash表中,使用较少,一般是memory引擎使用;因为使用hash表存储,按照常理,hash的性能比B-TREE效率高很多。
hash索引的缺点:
1,hash索引只能适用于精确的值比较,=,in,或者<>, 因为只需要经过一次算法即可找到相应的键值;
2,无法使用索引排序,因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索;
3,组合hash索引无法使用部分索引,以及like ‘xxx%’ 这样的部分模糊查询(这种部分模糊查询,其实本质上也是范围查询);
4,如果大量索引hash值相同,性能较低;
fulltext
全文检索索引,效率低,限制多
B-tree
针对空间数据索引,使用很少

mysql索引实现

1.MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。
2.虽然InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同。
第一个重大区别是InnoDB的数据文件本身就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。
3聚集索引:
是指数据库表行中数据的物理顺序与键值的逻辑(索引)顺序相同。
聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据
非聚簇索引:将数据存储于索引分开结构,索引结构的叶子节点指向了数据的对应

索引的利弊

1,索引的好处:
1,提高表数据的检索效率;
2,如果排序的列是索引列,大大降低排序成本;
3,在分组操作中如果分组条件是索引列,也会提高效率;
2,索引的问题:索引需要额外的维护成本;

sql优化原则

1 优先优化高并发低消耗的SQL;
1,1小时请求1W次,1次10个IO;
2,1小时请求10次,1次1W个IO;
从IO消耗,优化难度,CPU消耗进行比较;
定位性能瓶颈;
1,SQL运行较慢有两个影响原因,IO和CPU,明确性能瓶颈所在;
2,明确优化目标;
2.用小结果集驱动大结果集,减少外层循环的数据量:
如果小结果集和大结果集连接的列都是索引列,mysql在内连接时也会选择用小结果集驱动大结果集,因为索引查询的成本是比较固定的,这时候外层的循环越少,join的速度便越快。
3在索引中完成排序
4.使用最小的cloumn量
5。使用最有效的过滤条件

数据库中间件

mycat
<met<meta charset="utf-8">

SpringBoot+Mycat+MySQL实现分表分库案例

关于分库分表,Mycat已经帮我们在内部实现了路由的功能,我们只需要在Mycat中配置以下切分规则即可,对于开发者来说,我们就可以把Mycat看做是一个数据库,接下来我们开始搭建环境:

步骤一:

Mycat是使用java写的数据库中间件,所以要运行Mycat前要准备要jdk的环境,要求是jdk1.7以上的环境。所以需要在系统中配置JAVA_HOME的环境变量.

步骤二:

从官网下载Mycat,http://dl.mycat.io/1.6-RELEASE/ 我们是基于CentOS7来搭建Mycat环境的,所以下载版本:
Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

步骤三:

将下载好的安装包上传到服务器上并解压.解压之后目录结构如下:

image
步骤四:

配置切分规则:
将如下配置复制粘贴覆盖mycat/conf/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">
            <table name="user" primaryKey="id" dataNode="dn01,dn02" rule="rule1" />  
    </schema>

    <!-- 设置dataNode 对应的数据库,及 mycat 连接的地址dataHost -->  
    <dataNode name="dn01" dataHost="dh01" database="db01" />  
    <dataNode name="dn02" dataHost="dh01" database="db02" />   

    <!-- mycat 逻辑主机dataHost对应的物理主机.其中也设置对应的mysql登陆信息 -->  
    <dataHost name="dh01" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native">  
            <heartbeat>select user()</heartbeat>  
            <writeHost host="server1" url="127.0.0.1:3306" user="root" password="WolfCode_2017"/>  
    </dataHost> 
</mycat:schema>

<schema>:表示的是在mycat中的逻辑库配置,逻辑库名称为:TESTDB

<table>:表示在mycat中的逻辑表配置,逻辑表名称为:user,映射到两个数据库节点dataNode中,切分规则为:rule1(在rule.xml配置)

<dataNode>:表示数据库节点,这个节点不一定是单节点,可以配置成读写分离.

<dataHost>:真实的数据库的地址配置

<heartbeat>:用户心跳检测

<writeHost>:写库的配置

将如下配置复制粘贴覆盖mycat/conf/rule.xml的内容。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <tableRule name="rule1">
        <rule>
            <columns>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>
</mycat:rule>

这里定义的是切分规则,是按照id列进行切分,切分规则是采取取模的方式,
<property name="count">2</property>:这里配置了我们有拆分了多个库(表),需要和前面配置
<table name="user" primaryKey="id" dataNode="dn01,dn02" rule="rule1" />
中的dataNode个数一致,否则会出错.

步骤五:

在数据库中创建两个数据库db01,db02.
每个库中执行如下建表语句:

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

步骤六:

启动mycat,执行mycat/bin/startup_nowrap.sh

步骤七:

项目已经上传到github
https://github.com/javalanxiongwei/springboot-mycat
搭建SpringBoot环境,执行插入语句.
application.properties配置如下:

#配置数据源
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
#这里配置的是Mycat中server.xml中配置账号密码,不是数据库的密码。
spring.datasource.druid.username=root
spring.datasource.druid.password=123456
#mycat的逻辑库 端口也是mycat的
spring.datasource.druid.url=jdbc:mysql://192.168.142.129:8066/TESTDB

UserMapper.java代码如下:

@Mapper
public interface UserMapper {
    @Insert("insert into user(id,name) value (#{id},#{name})")
    int insert(User user);
    @Select("select * from user")
    List<User> selectAll();
}

UserController.java代码如下:

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserMapper userMapper;
    @RequestMapping("/save")
    public String save(User user){
        userMapper.insert(user);
        return "保存成功";
    }
    @RequestMapping("/list")
    public List<User> list(){
        return userMapper.selectAll();
    }
}

步骤八:

测试:
在地址栏输入:
http://localhost:8080/user/save?id=1&name=tom
http://localhost:8080/user/save?id=2&name=jack
查看数据库发现:
id为1的数据插入到数据库db02中的user表。
id为2的数据插入到数据库db01中的user表。
在地址栏输入:
http://localhost:8080/user/list
是可以看到刚刚插入的两条记录.

好到这一步我们就已经完成了分表分库了.

链接:https://www.jianshu.com/p/f81422b1c915
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
a charset="utf-8">

SpringBoot+Mycat+MySQL实现分表分库案例

关于分库分表,Mycat已经帮我们在内部实现了路由的功能,我们只需要在Mycat中配置以下切分规则即可,对于开发者来说,我们就可以把Mycat看做是一个数据库,接下来我们开始搭建环境:

步骤一:

Mycat是使用java写的数据库中间件,所以要运行Mycat前要准备要jdk的环境,要求是jdk1.7以上的环境。所以需要在系统中配置JAVA_HOME的环境变量.

步骤二:

从官网下载Mycat,http://dl.mycat.io/1.6-RELEASE/ 我们是基于CentOS7来搭建Mycat环境的,所以下载版本:
Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

步骤三:

将下载好的安装包上传到服务器上并解压.解压之后目录结构如下:

image
步骤四:

配置切分规则:
将如下配置复制粘贴覆盖mycat/conf/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">
            <table name="user" primaryKey="id" dataNode="dn01,dn02" rule="rule1" />  
    </schema>

    <!-- 设置dataNode 对应的数据库,及 mycat 连接的地址dataHost -->  
    <dataNode name="dn01" dataHost="dh01" database="db01" />  
    <dataNode name="dn02" dataHost="dh01" database="db02" />   

    <!-- mycat 逻辑主机dataHost对应的物理主机.其中也设置对应的mysql登陆信息 -->  
    <dataHost name="dh01" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native">  
            <heartbeat>select user()</heartbeat>  
            <writeHost host="server1" url="127.0.0.1:3306" user="root" password="WolfCode_2017"/>  
    </dataHost> 
</mycat:schema>

<schema>:表示的是在mycat中的逻辑库配置,逻辑库名称为:TESTDB

<table>:表示在mycat中的逻辑表配置,逻辑表名称为:user,映射到两个数据库节点dataNode中,切分规则为:rule1(在rule.xml配置)

<dataNode>:表示数据库节点,这个节点不一定是单节点,可以配置成读写分离.

<dataHost>:真实的数据库的地址配置

<heartbeat>:用户心跳检测

<writeHost>:写库的配置

将如下配置复制粘贴覆盖mycat/conf/rule.xml的内容。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <tableRule name="rule1">
        <rule>
            <columns>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>
</mycat:rule>

这里定义的是切分规则,是按照id列进行切分,切分规则是采取取模的方式,
<property name="count">2</property>:这里配置了我们有拆分了多个库(表),需要和前面配置
<table name="user" primaryKey="id" dataNode="dn01,dn02" rule="rule1" />
中的dataNode个数一致,否则会出错.

步骤五:

在数据库中创建两个数据库db01,db02.
每个库中执行如下建表语句:

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

步骤六:

启动mycat,执行mycat/bin/startup_nowrap.sh

步骤七:

项目已经上传到github
https://github.com/javalanxiongwei/springboot-mycat
搭建SpringBoot环境,执行插入语句.
application.properties配置如下:

#配置数据源
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
#这里配置的是Mycat中server.xml中配置账号密码,不是数据库的密码。
spring.datasource.druid.username=root
spring.datasource.druid.password=123456
#mycat的逻辑库 端口也是mycat的
spring.datasource.druid.url=jdbc:mysql://192.168.142.129:8066/TESTDB

UserMapper.java代码如下:

@Mapper
public interface UserMapper {
    @Insert("insert into user(id,name) value (#{id},#{name})")
    int insert(User user);
    @Select("select * from user")
    List<User> selectAll();
}

UserController.java代码如下:

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserMapper userMapper;
    @RequestMapping("/save")
    public String save(User user){
        userMapper.insert(user);
        return "保存成功";
    }
    @RequestMapping("/list")
    public List<User> list(){
        return userMapper.selectAll();
    }
}

步骤八:

测试:
在地址栏输入:
http://localhost:8080/user/save?id=1&name=tom
http://localhost:8080/user/save?id=2&name=jack
查看数据库发现:
id为1的数据插入到数据库db02中的user表。
id为2的数据插入到数据库db01中的user表。
在地址栏输入:
http://localhost:8080/user/list
是可以看到刚刚插入的两条记录.

好到这一步我们就已经完成了分表分库了.

链接:https://www.jianshu.com/p/f81422b1c915
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容