MYSQL最要的特点
- MYSQL的物理结构是索引组织表(Index Organized Table, IOT),不是堆表(Heap Table)。
- 数据就是索引,索引就是数据。记录之间是有顺序关系的。这种结构导致很多在oracle上得到的经验都失效了。在使用MYSQL之前一定要清楚这一点。
数据库设计
主键
- 因为mysql的表是IOT,所以每张表一定要有主键,必须要有主键。
- 如果没有主键,mysql会自动创建一个主键和主键索引。
- mysql所有的数据,也就是每条记录数据都是存放在主键索引中的。
- 这个和oracle中表数据和索引分开存储的方式是非常不同的。
- 在mysql中主键索引又叫聚簇索引(Clustered Index)。
- 表的主键是查询语句执行效率的关键点。
字符型数据
- mysql的字符型数据除了有字符集的区别外,还有有一个特殊地方就是需要指定字符集的比较策略(Collation)。
- 在不同比较策略下:
select 'A' = 'a' from dual;
- 这个语句会有不同的返回结果。
- 当数据库字符类型使用utf8mb4时,默认的Collation是utf8mb4_general_ci,忽略大小写。Collation 会影响语句的逻辑,索引的排序规则,检索效率。
- 强烈建议数据库字符类型使用utf8mb4,collation 使用utf8mb4_bin
- 在不同比较策略下:
#在配置文件中使用下面的参数;
default-character-set=utf8mb4
character-set-server=utf8mb4
collation_server=utf8mb4_bin
辅助索引,或者次级索引(Secondary Indexes)
- mysql的辅助索引和主键索引是非常不同的。
- 主键索引存储完整的数据,辅助索引不存储数据,只存储指向数据主键的引用。
- 当使用辅助索引查找数据时,总是先找到主键的引用,然后再从主索引上找到数据。这个操作叫回表。这种查询是比较慢的,尤其是数据量大,查询频繁的时候。
水平分表
- 水平分表:常见的就是月度数据。如果数据量很大话,尽量按月度分开建表存储。在oracle中可以使用分区表来实现。mysql虽然也提供了分区表技术,但是有很多限制,比如: 主键必须包含分区键,或者分区表上没有主键。
- 建议人为水平分表,更可控。当然,缺点就是应用的代码也需要修改。
垂直分表
- 垂直分表:常见的就是人员信息。把人员毕业证的照片,简历这些数据量比较大,平常又不查的数据存放到另外的表中。需要的时候,使用关联查询。
SQL优化
定位慢查询
# 启用慢查询日志,在配置文件中加入:
slow_query_log = 1
long_query_time = 2 #单位是秒,可以使用小数,0.2表示200毫秒。
slow_query_log_file = slow.log
log_queries_not_using_indexes = 1
Explain分析问题
- 主要关注:是否使用了索引、使用的索引是否合适
explain select count(1) from employees where emp_no < 20000;
- id //select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
- select_type //查询类型
- table //正在访问哪个表
- partitions //匹配的分区
- type //访问的类型
- possible_keys //显示可能应用在这张表中的索引,一个或多个,但不一定实际使用到
- key //实际使用到的索引,如果为NULL,则没有使用索引
- key_len //表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度
- ref //显示索引的哪一列被使用了,如果可能的话,是一个常数,哪些列或常量被用于查找索引列上的值
- rows //根据表统计信息及索引选用情况,大致估算出找到所需的记录所需读取的行数
- filtered //查询的表行占表的百分比
- Extra //包含不适合在其它列中显示但十分重要的额外信息
基本思路
- 各种数据库的性能问题基本上都是两大类:
- 减少 IO
- 减少CPU计算
- 为了解决这两个问题,从开发人员的方法上只有一种:
- 改变SQL的执行计划
常见方式
对于mysql有一些针对性的方法,如下:
- 尽量早过滤
- 少用子查询
- 尽量用join取代子查询
- 尽量少用or
- 尽量避免select *
- 用 union all 代替 union
- 在有索引的列上order by, group by
- 尽量避免在where中使用!=或<>操作符
- 尽量避免在where中对字段进行null值判断
- 尽量避免长事务
- 不要在索引列上计算
例: 必要时强制查询优化器使用某个索引
select * from t1 where nextprocess = 1 and processid in (8 , 32, 45)
select * from t1 use index (ix_processid) where nextprocess = 1 and processid in (8 , 32, 45);
-- 基本思路
--拒绝3B:
-- 大SQL (BIG SQL)
-- 大事务 (BIG Transaction)
-- 大批量 (BIG Batch)