1
0
mirror of https://gitee.com/tawords/tawords-docs synced 2025-09-02 07:53:28 +08:00
Code Issues Projects Releases Wiki Activity GitHub Gitee
Files
tawords-docs/docs/6. 【清单 ToDo】/数据库/MySQL数据库优化 & 设计注意事项(参考).md
2021-08-06 20:21:28 +08:00

133 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

参考资料:
https://www.cnblogs.com/daxian2012/p/11207510.html
------------
# 1.数据库设计和表创建时就要考虑性能
### 设计表时要注意:
- 表字段避免null值出现null值很难查询优化且占用额外的索引空间推荐默认数字0代替null。
- 尽量使用INT而非BIGINT如果非负则加上UNSIGNED这样数值容量会扩大一倍当然能使用TINYINT、SMALLINT、MEDIUM_INT更好。
- 使用枚举或整数代替字符串类型
- 尽量使用TIMESTAMP而非DATETIME
- 单表不要有太多字段建议在20以内
- 用整型来存IP
### 索引
- 索引并不是越多越好要根据查询有针对性的创建考虑在WHERE和ORDER BY命令上涉及的列建立索引可根据EXPLAIN来查看是否用了索引还是全表扫描
- 应尽量避免在WHERE子句中对字段进行NULL值判断否则将导致引擎放弃使用索引而进行全表扫描
- 值分布很稀少的字段不适合建索引,例如"性别"这种只有两三个值的字段
- 字符字段只建前缀索引
- 字符字段最好不要做主键
- 不用外键,由程序保证约束
- 尽量不用UNIQUE由程序保证约束
- 使用多列索引时主意顺序和查询条件保持一致,同时删除不必要的单列索引
简言之就是使用合适的数据类型,选择合适的索引
### 选择合适的数据类型
1使用可存下数据的最小的数据类型整型 < date,time < char,varchar < blob
2使用简单的数据类型整型比字符处理开销更小因为字符串的比较更复杂int类型存储时间类型bigint类型转ip函数
3使用合理的字段属性长度固定长度的表会更快使用enumchar而不是varchar
4尽可能使用not null定义字段
5尽量少用text非用不可最好分表
### 选择合适的索引列
1查询频繁的列在wheregroup byorder byon从句中出现的列
2where条件中<<==>>=betweenin以及like 字符串+通配符(%)出现的列
3长度小的列索引字段越小越好因为数据库的存储单位是页一页中能存下的数据越多越好
4离散度大不同的值多的列放在联合索引前面。查看离散度通过统计不同的列值来实现count越大离散程度越高
原开发人员已经跑路,该表早已建立,我无法修改,故:该措辞无法执行,放弃!
# 2.sql的编写需要注意优化
- 使用limit对查询结果的记录进行限定
- 避免select *,将需要查找的字段列出来
- 使用连接join来代替子查询
- 拆分大的delete或insert语句
- 可通过开启慢查询日志来找出较慢的SQL
- 不做列运算SELECT id WHERE age + 1 = 10任何对列的操作都将导致表扫描它包括数据库教程函数、计算表达式等等查询时要尽可能将操作移至等号右边
- sql语句尽可能简单一条sql只能在一个cpu运算大语句拆小语句减少锁时间一条大sql可以堵死整个库
- OR改写成INOR的效率是n级别IN的效率是log(n)级别in的个数建议控制在200以内
- 不用函数和触发器,在应用程序实现
- 避免%xxx式查询
- 少用JOIN
- 使用同类型进行比较,比如用'123'和'123'比123和123比
- 尽量避免在WHERE子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描
- 对于连续数值使用BETWEEN不用INSELECT id FROM t WHERE num BETWEEN 1 AND 5
- 列表数据不要拿全表要使用LIMIT来分页每页数量也不要太大
# 引擎
目前广泛使用的是MyISAM和InnoDB两种引擎
### MyISAM
MyISAM引擎是MySQL 5.1及之前版本的默认引擎,它的特点是:
- 不支持行锁,读取时对需要读到的所有表加锁,写入时则对表加排它锁
- 不支持事务
- 不支持外键
- 不支持崩溃后的安全恢复
- 在表有读取查询的同时,支持往表中插入新纪录
- 支持BLOB和TEXT的前500个字符索引支持全文索引
- 支持延迟更新索引,极大提升写入性能
- 对于不会进行修改的表,支持压缩表,极大减少磁盘空间占用
### InnoDB
InnoDB在MySQL 5.5后成为默认索引,它的特点是:
- 支持行锁采用MVCC来支持高并发
- 支持事务
- 支持外键
- 支持崩溃后的安全恢复
- 不支持全文索引
总体来讲MyISAM适合SELECT密集型的表而InnoDB适合INSERT和UPDATE密集型的表
MyISAM速度可能超快占用存储空间也小
# 分区
MySQL在5.1版引入的分区是一种简单的水平拆分,用户需要在建表的时候加上分区参数,对应用是透明的无需修改代码。
对用户来说分区表是一个独立的逻辑表但是底层由多个物理子表组成实现分区的代码实际上是通过对一组底层表的对象封装但对SQL层来说是一个完全封装底层的黑盒子。MySQL实现分区的方式也意味着索引也是按照分区的子表定义没有全局索引。
用户的SQL语句是需要针对分区表做优化SQL条件中要带上分区条件的列从而使查询定位到少量的分区上否则就会扫描全部分区可以通过EXPLAIN PARTITIONS来查看某条SQL语句会落在那些分区上从而进行SQL优化我测试查询时不带分区条件的列也会提高速度故该措施值得一试。
分区的好处是:
- 可以让单表存储更多的数据
- 分区表的数据更容易维护,可以通过清楚整个分区批量删除大量数据,也可以增加新的分区来支持新插入的数据。另外,还可以对一个独立分区进行优化、检查、修复等操作
- 部分查询能够从查询条件确定只落在少数分区上,速度会很快
- 分区表的数据还可以分布在不同的物理设备上,从而高效利用多个硬件设备
- 可以使用分区表赖避免某些特殊瓶颈例如InnoDB单个索引的互斥访问、ext3文件系统的inode锁竞争
- 可以备份和恢复单个分区
分区的限制和缺点:
- 一个表最多只能有1024个分区
- 如果分区字段中有主键或者唯一索引的列,那么所有主键列和唯一索引列都必须包含进来
- 分区表无法使用外键约束
- NULL值会使分区过滤无效
- 所有分区必须使用相同的存储引擎
分区的类型:
- RANGE分区基于属于一个给定连续区间的列值把多行分配给分区
- LIST分区类似于按RANGE分区区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择
- HASH分区基于用户定义的表达式的返回值来进行选择的分区该表达式使用将要插入到表中的这些行的列值进行计算。这个函数可以包含MySQL中有效的、产生非负整数值的任何表达式
- KEY分区类似于按HASH分区区别在于KEY分区只支持计算一列或多列且MySQL服务器提供其自身的哈希函数。必须有一列或多列包含整数值
具体关于mysql分区的概念请自行google或查询官方文档
# 分表
分表就是把一张大表,按照如上过程都优化了,还是查询卡死,那就把这个表分成多张表,把一次查询分成多次查询,然后把结果组合返回给用户。
分表分为垂直拆分和水平拆分通常以某个字段做拆分项。比如以id字段拆分为100张表 表名为 tableName_id%100
但:分表需要修改源程序代码,会给开发带来大量工作,极大的增加了开发成本,故:只适合在开发初期就考虑到了大量数据存在,做好了分表处理,不适合应用上线了再做修改,成本太高!!!而且选择这个方案,都不如选择我提供的第二第三个方案的成本低!故不建议采用。
# 分库
把一个数据库分成多个,建议做个读写分离就行了,真正的做分库也会带来大量的开发成本,得不偿失!不推荐使用。