MYSQL优化思路

数据库配置上分为索引设置和参数设置(主要是各个buffer size);另个方面在数据操作上,避触发MYSQL耗时、耗CPU操作

数据库设置

  • 索引
    • 覆盖索引:避免回表
    • order by
      • 未加索引的情况,order by依据数据量会进行以下排序策略:
        • sort buffer足够大: 全字段排序
        • sort buffer不太够: rowid排序+回表
        • sort buffer不够:临时文件归并排序
      • 加索引的情况
        • 索引未覆盖到所有选择列:回表
        • 索引覆盖到所有选择列:无需回表,直接输出
    • group by
      • 未加索引情况下,建立临时表,记录依次upsert插入临时表,最后默认再进行排序(如无需排序,建议:group by f order by null
      • 加索引情况下,直接顺序累加,不再走temporaryfile sort
    • join
      • 被驱动表上没索引,走BNL:
        • 如果join buffer足够大能装得下被驱动表,扫描行N+M,判断次数N*M,无论大表还是小表作为驱动表效率一样
        • 如果join buffer不够大不能装下被驱动表,扫描行N+(N/join_buffer_size+1)M,判断次数NM,由扫描行公示可知,被驱动表N越小,扫描次数越少
      • 被动驱动表上有索引,走NLJ:
        • 扫描的N条待匹配记录,每一条都根据索引树查找,复杂度是log2M,如果算上回表的话,那就是2log2M。所以整体时间复杂度是N+N2*log2M,N越小越好即被驱动表越小越好
  • buffer设置大小

    • 数据页缓存大小
      • 减少频繁换页造成的io
      • 避免降低缓存命中率
    • 被驱动表上没索引,走BNL的话,尽量增大join buffer,如果驱动表过大,一次性装不下,则会触发分段join
      • 扫描次数增多,(驱动表/join_buffer+1)倍数,影响到缓存页淘汰机制,降低缓存页命中率——如果被驱动表是张大冷表,重复加载比较,会从LRU_young进入到LRU_old中
      • 造成了”长事务”

        数据库操作

  • 数据页合并、数据页分裂

    • 随机插入和删除,如uuid方式新增
    • 减少行冲突:死锁检测耗费cpu
    • 将冲突高的sql或行放在事务后面执行:二阶段锁协议
  • 避免大(长)事务
    • 长期占用MDL读锁,导致DDL拿不到MDL写锁
    • undolog不能回收,空间膨胀
    • 主从延迟
    • 高并发下,数据库连接池容易撑爆