基础
MySQL
MySQL
  • 基础知识
    • MySQL 的安装与配置
      • Windows
        • 安装
        • 配置文件
      • Linux
        • 安装
        • 配置文件
      • docker
      • mysql 配置文件格式
    • MySQL 查询的执行过程
      • MySQL 的客户端/服务器通信协议
      • MySQL 查询优化器
        • 优化器可能选择错误的执行计划
        • MySQL 能够处理的优化类型
          • 优化 COUNT()、MIN() 和 MAX()
          • 预估并转化为常数表达式
          • 提前终止查询
          • 排序优化
      • MySQL如何执行联接查询
    • 事务
      • ACID
      • 隔离级别
      • 死锁
      • 事务日志
      • 两阶段锁定协议
      • 多版本并发控制(MVCC)
  • SQL 优化
    • schema 设计
      • 选择数据类型
        • 整数类型
        • 实数类型
        • 字符串类型
          • VARCHAR 和 CHAR
          • BINARY 和 VARBINARY
          • BLOB 和 TEXT
          • ENUM 和 SET
        • 日期类型
      • 选择标识符
    • 索引
      • HASH 索引
      • B-tree 索引
      • 聚簇索引
      • 覆盖索引
      • 前缀索引和索引的选择性
      • 索引合并
      • 选择合适的索引列顺序
      • 使用索引扫描来做排序
      • 维护索引和表
    • 查询优化
      • 优化 SQL 语句的一般步骤
        • 1. 通过 show status 命令了解各种 SQL 的执行频率
        • 2. 定位执行效率较低的 SQL 语句
        • 3. 通过 EXPLAIN 分析低效 SQL 的执行计划
        • 4. 通过 SHOW PROFILE 分析 SQL
        • 5. 通过 TRACE 分析优化器如何选择执行计划
        • 6. 确定问题并采取相应的优化措施
      • 两个简单实用的优化方法
      • 一个复杂查询还是多个简单查询
      • 常用 SQL 的优化
        • 大批量插入数据
        • 优化 GROUP BY 语句
        • 优化联接查询
        • 优化分页查询
        • 优化 SQL_CALC_FOUND_ROWS
        • 优化 UNION 查询
    • Performance Schema
      • 配置
      • 使用
        • 检查SQL语句
        • 检查预处理语句
        • 语句剖析
        • 检查读写性能
        • 检查内存使用情况
        • 检查变量
    • MySQL线程
    • 复制
      • 概述
        • 复制中的各类文件
        • 三种复制格式
        • 全局事务标识符(GTID)
        • 崩溃后的复制安全
      • 安装
        • 基于二进制日志文件位置的复制
        • 基于GTID的复制
      • 复制拓扑
        • 主动/被动模式
        • 主动/只读池模式
        • 多级复制架构
  • 其他
    • 查询缓存
    • 批量insert
    • MySQL 锁的类型
    • MySQL 的索引有哪些
    • INSERT ... ON DUPLICATE KEY UPDATE Statement
由 GitBook 提供支持
在本页
  • schema 的设计原则
  • 设计陷阱
  • 太多的列
  • 太多的联接
  • NULL 不是虚拟值
  • 当心自动生成的 schema
  1. SQL 优化

schema 设计

schema 的设计原则

  1. 尽量避免在设计中出现极端情况,例如,强制执行非常复杂的查询或者包含很多列的表设计(很多的意思是介于有点多和非常多之间)。

  2. 使用小的、简单的、适当的数据类型,并避免使用 NULL。

  3. 尝试使用相同的数据类型来存储相似或相关的值,尤其是在联接条件中使用这些值时。

  4. 注意可变长度字符串,它可能会导致临时表和排序的全长内存分配不乐观。

  5. 如果可能的话,尝试使用整数作为标识符。

  6. 避免使用一些传统的 MySQL 技巧,例如,指定浮点数的精度或整数的显示宽度。

  7. 小心使用 ENUM 和 SET 类型。它们很方便,但也可能被滥用,有时还很棘手。另外最好避免使用 BIT 类型。

请记住,你的 schema 将随着业务需求和用户数据而发展,这意味着拥有一个强大的软件生命周期来管理 schema 更改是使这种发展在组织中安全且可扩展的关键部分。

设计陷阱

太多的列

MySQL 的存储引擎 API 通过在服务器和存储引擎之间以行缓冲区格式复制行来工作;然后,服务器将缓冲区解码为列。将行缓冲区转换为具有解码列的行数据结构的操作代价是非常高的,而这种转换的成本取决于列数。

太多的联接

所谓的实体属性值(entity attribute value,EAV)设计模式是一种被普遍认为糟糕的设计模式的典型案例,尤其是在 MySQL 中效果不佳。

MySQL 限制每个联接有 61 个表,而 EAV 模式设计的数据库需要许多自联接。

一个粗略的经验法则是,如果需要以高并发性快速执行查询,那么每个查询最好少于十几个的表。

NULL 不是虚拟值

当需要表示未知值时,不要太害怕使用 NULL。

在某些情况下,使用 NULL 比使用某个虚拟常数更好。从受约束类型的域中选择一个值,例如使用 -1 表示一个未知的整数,可能会使代码复杂化,容易引入 bug,并通常会把事情搞得一团糟。处理 NULL 并不容易,但通常比其他替代方案更好。

当心自动生成的 schema

写得不好的 schema 迁移程序和自动生成 schema 的程序可能会导致严重的性能问题。有些程序存储任何数据都会使用很大的 VARCHAR 字段,或者对将在联接中进行比较的列使用不同的数据类型。

如果 schema 是自动生成的,一定要反复检查确认没有问题。

对象关系映射(ORM)系统(以及使用它们的“框架”)通常是另一个性能“噩梦”。其中一些 ORM 系统会将任意类型的数据存储到任意类型的后端数据存储中,这通常意味着其没有设计使用更优的数据存储。

“对开发人员隐藏复杂性”的应用程序通常不能很好地扩展。建议在用性能交换开发人员的效率之前仔细考虑,并始终在实际的大型数据集上进行测试,这样就不会太晚才发现性能问题。

上一页多版本并发控制(MVCC)下一页选择数据类型

最后更新于8个月前