mysql

120 阅读6分钟

1.myIsam和innodb区别

  • MyISAM锁的粒度是表级的,而InnoDB支持行级锁
  • MyISAM支持全文类型索引,而InnoDB不支持全文索引
  • innodb是基于聚簇索引建立的,支持事务,外健,并且通过mvcc支持高并发,索引和数据存储在一起。
  • myIsam,不支持事务,支持、压缩、空间函数等。不支持外健,索引和数据分开存储。一般用于大量查询,少量插入。

2.mysql索引有哪些,聚簇索引和非聚簇索引又是什么?

索引按照数据结构主要包含B+树和Hash索引。

聚簇索引:

  • 如果表设置了主键,主键就是聚簇索引;
  • 如果没有主键,则会默认第一个notnull,且唯一的(UNIQUE)的列作为聚簇索引。
  • 以上都没有,则默认创建一个隐藏的row_id作为聚簇索引
  • innodb聚簇索引叶子节点存储的是行数据

查找过程:如果按照主键查询,只需要扫描一次B+树就可以通过聚簇索引定位到行记录数据

非聚簇索引:

  • innodb的普通索引叶子节点存储的是主键(聚簇索引)的值,而MyIsam普通索引存储的是记录指针。

查找过程:如果按照普通索引需要,扫描两次B+树,第一次通过非聚簇索引找到聚簇索引值,第二次根据聚簇索引找到行数据。

回表查询:

非聚簇索引查找过程,扫描两次B+树。

覆盖索引:

只需要在一棵树上就能获取SQL所需要的数据,无需回表。

explain的输出结果Extra字段为Using index时,能够触发索引覆盖。

将被查询的字段,建立联合索引。B+树上就有相应的行数据。

场景:分页查询,全表count。

3.mysql锁类型

分为共享锁和排他锁,也叫读锁和写锁。

读锁是共享的,可以通过lock in share mode实现,这时候只能读不能写。

写锁是排他的,它会阻塞其他的读锁和写锁。从颗粒度来区分又分为行锁和表锁。

表锁会锁定整张表,并且阻塞其他用户对该表的所有读写操作,比如alter修改表结构,进行锁表。

行锁又可以分为悲观锁和乐观锁。悲观锁通过for update实现,乐观锁则通过版本号实现。

4.分库分表

数据量:每天几万,流水几十万。

先分库再分表。

垂直分库:按照微服务不同模块分库。

垂直分表:表字段过多,将不常用的数据拆分。(不常用,在设计表的时候就要避免)

水平分表:按照500万每张表,按照业务场景决定用什么字段作为分表字段(sharding_key)。

保证各个表ID唯一性:雪花算法id,设置步长。

分布到各个表中:

Hash:比如用户id为100,那我们都经过hash(100),然后对(表数量)取模,就可以落到对应的表上了。

range:固定步长。

分表后非sharding_key查询:

  • 做映射表
  • es

5.读写分离

使用shrading- JDBC实现读写分离(可以认为是一个增强版的jdbc驱动),数据源完全由shrading托管,写操作自动执行master库,读操作自动执行salve库。

spring:
  main:
    allow-bean-definition-overriding: true
  shardingsphere:
    datasource:
      names:
        master,slave
      # 主数据源
      master:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_master?characterEncoding=utf-8
        username: ****
        password: ****
      # 从数据源
      slave:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_slave?characterEncoding=utf-8
        username: ****
        password: ****
    masterslave:
      # 负载均衡算法类型:round_robin(轮询),Random(随机)
      load-balance-algorithm-type: round_robin
      # 最终的数据源名称
      name: dataSource
      # 主库数据源名称
      master-data-source-name: master
      # 从库数据源名称列表,多个逗号分隔
      slave-data-source-names: slave
    props:
      # 开启SQL显示,默认false,打印sql,显示执行库的名称
      sql:
        show: true

6.读写分离架构中读延迟问题

主节点写入数据后需要同步到从数据库,mysql5.7的主从复制采用多线程,但还是可能有延迟。

解决方式:

  • 业务层面妥协,是否操作后马上进行读取

  • 业务上不能妥协,对这类操作直接走主库,shrding-jdbc可以设置强制走主库。

    //-----------------------------------核心    跟pagehelper 分页插件类似  只作用于最近的一条查询语句,
    HintManager.getInstance().setMasterRouteOnly();  
    List<Order> byUserId = orderMapper.findByUserId(5);
    
    

7.varchar和char区别

1.char长度固定,如果字符不够,会用空格填充到特定长度,检索char值需要删除尾部空格。

2.varchar不会填充空格。

8.like的%放在字符前和后有什么区别?

  • 放在字符前,会进行全表扫描。
  • 放在字符后,如果是字符类型的字段且加索引,那么会走索引。如果是数字类型,那么不走索引,因为查询时是按照字符查询的。

9.mysql索引类型

  • 主键索引
  • 唯一索引 unique
  • 普通索引 normal
  • full text 全文索引
  • 索引译B+树存储

10.B树和B+树的区别

B树:每个节点都存储key和data,并且叶子节点指针为null。

B+树:只有叶子节点存储data,叶子节点包含了这颗树的所有键值。

为什么innodb要使用B+树,因为B+树内节点不存储data,这样一个节点就可以存储更多的key。

11.联合索引最左原则

  • mysql会一直向右匹配知道遇到范围查询(>,<,between,like)就停止匹配,

  • =和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。

  • 选择热度最高的列作为联合索引左列

  • 索引的底层是一颗B+树,联合索引的健值数量不是一个,而是多个。构建一颗B+树只能根据一个值来构建,因此数据库依据联合索引最左的字段来构建B+树。例子:假如创建一个(a,b)的联合索引,那么它的索引树是这样的 image

12.索引规范

  • 尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录。
  • 尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。