• MySQL索引、锁和优化


    MySQL

    1.索引

    • 定义: 索引是存储引擎用于快速找到记录的一种数据结构

    • 作用: 索引可快速访问数据库表中的特定信息,索引是对一列或多列值进行排序的数据结构

    • 实现: 索引是在存储引擎层实现,不是服务层,不同的存储引擎具有不同的索引类型和实现

    索引优化是对查询性能优化最有效的手段(索引能轻易将查询性能提高几个数量级)

    2.索引的类型

    • B+Tree索引
    • 哈希索引
    • 全文索引
    • 空间数据索引

    2.1 B+Tree索引

    MySQL多数存储引擎的默认类型

    利用索引,不再需要建立全表扫描来获取需要的数据

    B+Tree索引:

    • 全键值查找
    • 键值范围查找
    • 键前缀值查找

    最左前缀查找

    B+Tree相比于BTree的优势

    • B+Tree非叶子结点只存储索引,B+Tree的高度更低,IO次数更少
    • B+Tree叶子节点前后管理,更加方便范围查询,结果都在叶子节点,查询效率稳定
    • B+Tree有利于对数据扫描,避免BTree的回溯扫描

    2.2 哈希索引

    哈希索引基于哈希表实现,哈希索引查找的速度非常快

    哈希索引无法实现排序

    CRC32(column) 计算哈希

    3.索引的优点

    • 可以大大较少服务器需要扫描的数据量
    • 帮助服务器避免排序和临时表
    • 索引可以将随机I/O变成顺序I/O

    索引的原则:

    • 索引不是越多越好,维护索引需要空间和时间

    • 频繁更新的数据,不宜建立索引

    • 数据量较少的表(数据量超大)的表没必要建立索引

    • 重复率小的列建立索引

    • 数据具有唯一性,建立索引

    • 频繁group by ,order by的列,建立索引

    • 经常用于查询条件的字段建议生成索引

    4.高性能索引

    正确的创建使用索引是实现高性能查询的基础

    4.1独立的列

    索引不能是表达式的一部分,不能是函数的参数

    • 无法启动列索引
    SELECT actor_id FROM actor WHERE actor_id + 1 = 5;
    
    • 可以启动actor_id的索引
    SELECT actor_id FROM actor WHERE actor_id  = 4;
    

    4.2 前缀索引和索引选择性

    对于很长的字符列,建立索引会让索引变得大且慢

    • 1.找到合适的索引字符长度
    • 2.创建前缀索引
    ALTER TABLE city_demo ADD KEY (city(7));   # 索引字符长度为7
    

    4.3多列索引

    常见的错误:为每个列创建独立的列

    4.4选择合适的索引列顺讯

    • 对于多个索引列,可先查看列对应数据基数
    SELECT sum(staff_id = 2),SUM(customer_id = 584) FROM payment;
    
    # SUM(staff_id = 2):7972
    # SUM(customer_id = 584) :30
    
    SELECT COUNT(DISTINCT staff_id)/COUNT(*) as staff_id_selectivity,
           COUNT(DISTINCT customer_id)/COUNT(*) as customer_id_selectivity,
           COUNT(*)
    FROM payment;
    
    

    选择性较高的作为索引列的第一列,应该将 customer_id 放到前面

    5.查询性能优化

    除了建立最好的索引,还需要合理的设计查询

    优化三驾马车,需要齐头并进

    • 查询优化
    • 索引优化
    • 库表结构优化

    5.1 慢查询基础

    查询性能低下最基本的原因是访问的数据太多,大部分可以通过减少访问的数据量方式进行优化

    • 1.确认应用程序是否在检索大量超过需要的数据(过多的行,过多的列)
    • 2.确认MySQL服务器是否存在分析大量超过需要的数据行

    请求不需要的数据

    扫描额外的记录

    • 响应时间 = 服务时间 + 排队时间
    • 扫描的行数
    • 返回的行数

    5.2 重构查询方式

    复杂查询 vs 简单查询

    切分查询

    DELETE FROM messages WHERE created < DATA_SUB(NOW(),INTERVAL 3 MONTH);
    
    # 优化
    # 对大量删除数据进行切分,防止服务器一次性完成大量工作
    # 锁住很多数据,占满整个事务日志,耗尽系统资源,阻塞小且重要的查询
    row_affected = 0
    do{
    	 row_affected = do_query(
         "DELETE FROM messages WHERE created < DATA_SUB(NOW(),INTERVAL 3 MONTH) LIMIE 10000")
    }while row_affected > 0
    

    5.3 分解关联查询

    • 缓存的效率更高
    • 分解成单个查询,可以减少锁的竞争
    • 应用层关联,更加容易对数据库进行拆分(做到高性能和可扩展)
    • 减少冗余记录的查询
    • 引用层实现哈希关联代替MySQL的嵌套循环关联(IN 的方式代替关联查询)
    # 查询当前会话的Last_query_cost的值来计算当前查询的成本
    SHOW STATUS LIKE 'Last_query_cost';
    

    6.主从复制

    主要涉及三个线程

    • binlog线程 - 负责将主服务器上的数据更改写入二进制日志(Binary log)中
    • I/O线程 - 负责从主服务器读取二进制日志,并写入从服务器的中继日志(Relay log)
    • SQL线程 - 负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中重放(Replay)

    读写分离提高性能

    • 主服务器处理写操作
    • 从服务器处理读操作

    主从服务器负责各自的读和写,极大程度缓解了锁的争用

    从服务器可以使用MyISAM,提升查询性能以及节约系统开销

    增加冗余,提高可用性

    实现:

    • 增加反向代理(Reverse Proxy),代理服务器接受应用层传来的读写请求,决定转发道那个服务器

    7.MySQL语句执行流程

    Server层

    • 连接器
    • 查询缓存(MySQL 8.0版本后取消)
    • 分析器
    • 优化器
    • 执行器

    存储引擎层

    • 数据的存储和读取

    8.MySQL中的锁

    • 悲观锁
    • 乐观锁

    间隙锁: Gap Lock

    行锁只能锁住行,如果在记录之间插入数据就无法解决,引入间隙锁[左开右闭区间]

    间隙锁+行锁 = NextKeyLock

    • 当前读(加悲观锁的实现,SELECT FOR UPDATE ,DELETE)
    • 快照读(不加锁)
    不要用狭隘的眼光看待不了解的事物,自己没有涉及到的领域不要急于否定. 每天学习一点,努力过好平凡的生活.
  • 相关阅读:
    SAE/ISO standards for Automotive
    The J1850 Core
    SAE J1708 DS36277 MAX3444, DS75176B
    X431 元征诊断枪
    凯尔卡C68全球版汽车电脑诊断仪
    汽车王牌
    Vehicle’s communication protocol
    Vehicle Network Protocols -- ISO/KWP CAN CCD PCI SCI / SCP / Class 2
    On-board diagnostics -- Standards documents
    On-board diagnostics connector SAE J1962
  • 原文地址:https://www.cnblogs.com/GeekDanny/p/15057808.html
Copyright © 2020-2023  润新知