Mysql 36条军规

一、核心军规

1.尽量不在数据库做运算

1、别让脚趾头想事情

2、那是脑瓜子的职责

3、让数据库多做她擅长的事:

(1)尽量不在数据库做运算

(2)复杂运算移动到程序端CPU

(3)尽可能简单应用MySQL

反例:md5() / Order by Rand()

2.控制单表数据量

1、一年内的单表数据量预估

(1)纯INT不超1000W

(2)含CHAR不超500W

2、合理分表不超载

(1)USERID

(2)DATE

(3)AREA

(4)….

3、建议单库不超过300-400个表

3.保持表身段苗条

1、表字段数少而精

(1)IO高效

(2)全表遍历

(3)表修复快

(4)提高并发

(5)alter table快

2、单表多少字段合适?

3、单表1G体积 500W行评估

(1)顺序读1G文件需N秒

(2)单行不超过200Byte

(3)单表不超50个纯INT字段

(4)单表不超20个CHAR(10)字段

4、单表字段数上限控制在20~50个

4.平衡范式不冗余

1、严格遵循三大范式?

2、效率优先、提升性能

3、没有绝对的对与错

4、适当时牺牲范式、加入冗余

5、但会增加代码复杂度

5.拒绝3B

1、数据库并发像城市交通

(1)非线性增长

2、拒绝3B

(1)大SQL (BIG SQL)

(2)大事务 (BIG Transaction)

(3)大批量 (BIG Batch)

二、字段类军规

6.用好数值字段类型

1、三类数值类型:

(1)TINYINT(1Byte)

(2)SMALLINT(2B)

(3)MEDIUMINT(3B)

(4)INT(4B)、BIGINT(8B)

(5)FLOAT(4B)、DOUBLE(8B)

(6)DECIMAL(M,D)

反例:INT(1) VS INT(11)、BIGINT AUTO_INCREMENT、DECIMAL(18,0)

7.将字符转化为数字

1、数字型VS字符串型索引

(1)更高效

(2)查询更快

(3)占用空间更小

正例:用无符号INT存储IP,而非CHAR(15)

(1) INT UNSIGNED

(2)INET_ATON()

(3)INET_NTOA()

8.优先使用ENUM或SET

1、优先使用ENUM或SET

(1)字符串

(2)可能值已知且有限

2、存储

(1)ENUM占用1字节,转为数值运算

(2)SET视节点定,最多占用8字节

(3)比较时需要加‘ 单引号(即使是数值)

正例:(1)`sex` enum('F','M') COMMENT '性别'

(2)`c1` enum('0','1','2','3') COMMENT '职介审核'

9.避免使用NULL字段

1、避免使用NULL字段

(1)很难进行查询优化

(2)NULL列加索引,需要额外空间

(3)含NULL复合索引无效

正例:(1)`c` int(10) NOT NULL DEFAULT 0

反例:(1)`a` char(32) DEFAULT NULL

(2)`b` int(10) NOT NULL

10.少用并拆分TEXT/BLOB

1、TEXT类型处理性能远低亍VARCHAR

(1)强制生成硬盘临时表

(2)浪费更多空间

(3)VARCHAR(65535)==>64K (注意UTF-8)

2、尽量不用TEXT/BLOB数据类型

3、若必须使用则拆分到单独的表

正例:

CREATE TABLE t1 (

id INT NOT NULL AUTO_INCREMENT,

data text NOT NULL,

PRIMARY KEY (id)?

) ENGINE=InnoDB;

11.不在数据库里存图片

三、索引类军规

12.谨慎合理添加索引

1、谨慎合理添加索引

(1) 改善查询

(2)减慢更新

(3) 索引不是越多越好

2、能不加的索引尽量不加

(1)综合评估数据密度和数据分布

(2)最好不超过字段数20%

3、结合核心SQL优先考虑覆盖索引

正例:不要给“性别”列创建索引

13.字符字段必须建前缀索引

1、区分度

(1)单字母区分度:26

(2)4字母区分度:26*26*26*26=456,976

(3)5字母区分度:26*26*26*26*26=11,881,376

(4)6字母区分度:26*26*26*26*26*26=308,915,776

2、字符字段必须建前缀索引

`pinyin` varchar(100) DEFAULT NULL COMMENT '小区拼音',

KEY `idx_pinyin` (`pinyin`(8)),

) ENGINE=InnoDB

14.不在索引列做运算

1、不在索引列进行数学运算或函数运算

(1)无法使用索引

(2)导致全表扫描

正例:select * from table WHERE date_col >= DATE_SUB('2011-10-22',INTERVAL 10 DAY);

反例:select * from table WHERE to_days(current_date) – to_days(date_col) <= 10

15.自增列或全局ID做INNODB主键

1、对主键建立聚簇索引

2、二级索引存储主键值

3、主键不应更新修改

4、按自增顺序插入值

5、忌用字符串做主键

6、聚簇索引分裂

7、推荐用独立于业务的AUTO_INCREMENT列或全局ID生成器做代理主键

8、若不指定主键,InnoDB会用唯一且非空值索引代替

16.尽量不用外键

1、线上OLTP系统(线下系统另论)

(1)外键可节省开发量

(2)有额外开销

(3)逐行操作

(4)可‘到达’其它表,意味着锁

(5)高并发时容易死锁

2、由程序保证约束

四、SQL类军规

17.SQL语句尽可能简单

1、大SQL VS 多个简单SQL

(1)传统设计思想

(2)BUT MySQL NOT

(3)一条SQL只能在一个CPU运算

(4)5000+ QPS的高并发中,1秒大SQL意味着?

(5)可能一条大SQL就把整个数据库堵死

2、拒绝大SQL,拆解成多条简单SQL

(1)简单SQL缓存命中率更高

(2)减少锁表时间,特别是MyISAM

(3)用上多CPU

18.保持事务(连接)短小

1、保持事务/DB连接短小精悍

(1)事务/连接使用原则:即开即用,用完即关

(2)不事务无关操作放到事务外面, 减少锁资源的占用

(3)不破坏一致性前提下,使用多个短事务代替长事务

举例:发贴时的图片上传等待

大量的sleep连接

19.尽可能避免使用SP/TRIG/FUNC

1、线上OLTP系统(线下库另论)精悍

(1)尽可能少用存储过程

(2)尽可能少用触发器

(3)减用使用MySQL凼数对结果进行处理

(4)由客户端程序负责

20.尽量不用 SELECT *

1、用SELECT * 时

(1)更多消耗CPU、内存、IO、网络带宽

(2)先向数据库请求所有列,然后丢掉不需要列?

2、尽量不用SELECT * ,另取需要数据列

(1)更安全的设计:减少表变化带来的影响

(2)为使用covering index提供可能性

(3)Select/JOIN减少硬盘临时表生成,特别是有TEXT/BLOB时

反例:SELECT * FROM tag WHERE id = 999184

正例:SELECT keyword FROM tag WHERE id = 999184

21.改写OR语句

1、改写OR为IN()

(1)同一字段,将or改写为in()

1)OR效率:O(n)

2)IN 效率:O(Log n)

3)当n很大时,OR会慢很多

(2)注意控制IN的个数,建议n小于200

反例:Select * from opp WHERE phone=‘12347856' or phone=‘42242233' ;

正例:Select * from opp WHERE phone in ('12347856' , '42242233') ;

2、改写OR为UNION

(1)不同字段,将or改为union

1)减少对不同字段进行 "or" 查询

2)Merge index往往很弱智

3)如果有足够信心:set global optimizer_switch='index_merge=off' ;

反例:Select * from opp WHERE phone='010-88886666' or cellPhone='13800138000';

正例:

Select * from opp WHERE phone='010-88886666'

union

Select * from opp WHERE cellPhone='13800138000';

22.避免负向查询和% 前缀模糊查询

1、避免负向查询

(1)NOT、!=、<>、!、NOT EXISTS、NOT IN、NOT LIKE等

2、避免 % 前缀模糊查询

(1)B+ Tree

(2)使用不了索引

(3)导致全表扫描

反例:

MySQL> select * from post WHERE title like '%北京%' ;

572 rows in set (3.27 sec)

正例:

MySQL> select * from post WHERE title like ‘北京%' ;

298 rows in set (0.01 sec)

23.减少COUNT(*)

1、MyISAM VS INNODB

(1)不带 WHERE COUNT()

(2)带 WHERE COUNT()

2、COUNT(*)的资源开销大,尽量不用少用

3、计数统计

(1)实时统计:用memcache,双向更新,凌晨跑基准

(2)非实时统计:尽量用单独统计表,定期重算

24.LIMIT高效分页

1、传统分页:

(1)Select * from table limit 10000,10;

2、LIMIT原理:

(1)Limit 10000,10

(2)偏移量越大则越慢

3、推荐分页:

(1)Select * from table WHERE id>=23423 limit 11;

#10+1 (每页10条)

(2)select * from table WHERE id>=23434 limit 11;

4、分页方式二

(1)Select * from table WHERE id >= ( select id from table limit 10000,1 ) limit 10;

5、分页方式三:

(1)SELECT * FROM table INNER JOIN (SELECT id FROM table LIMIT 10000,10) USING (id) ;

6、分页方式四:

(1)程序取ID:select id from table limit 10000,10;

(2)Select * from table WHERE id in (123,456…) ;

7、可能需按场景分析并重组索引

8、示例:

MySQL> select sql_no_cache * from post limit 10,10;

10 row in set (0.01 sec)

MySQL> select sql_no_cache * from post limit 20000,10;

10 row in set (0.13 sec)

MySQL> select sql_no_cache * from post limit 80000,10;

10 rows in set (0.58 sec)

MySQL> select sql_no_cache id from post limit 80000,10;

10 rows in set (0.02 sec)

MySQL> select sql_no_cache * from post WHERE id>=323423 limit 10;

10 rows in set (0.01 sec)

MySQL> select * from post WHERE id >= ( select sql_no_cache id from post limit 80000,1 ) limit 10 ;

10 rows in set (0.02 sec)

25.用UNION ALL 而非 UNION

1、若无需对结果进行去重,则用UNION ALL

(1)UNION有去重开销

2、举例:

MySQL>SELECT * FROM detail20091128 UNION ALL

SELECT * FROM detail20110427 UNION ALL

SELECT * FROM detail20110426 UNION ALL

SELECT * FROM detail20110425 UNION ALL

SELECT * FROM detail20110424 UNION ALL

SELECT * FROM detail20110423;

26.分解联接保证高并发

1、高并发DB不建议进行两个表以上的JOIN

2、适当分解联接保证高并发

(1)可缓存大量早期数据

(2)使用了多个MyISAM表

(3)对大表的小ID IN()

(4)联接引用同一个表多次

3、举例:

MySQL> Select * from tag JOIN tag_post on tag_post.tag_id=tag.id JOIN post on tag_post.post_id=post.id WHERE tag.tag=‘二手玩具’;

-->

MySQL> Select * from tag WHERE tag=‘二手玩具’;

MySQL> Select * from tag_post WHERE tag_id=1321;

MySQL> Select * from post WHERE post.id in (123,456,314,141)

27.GROUP BY 去除排序

1、GROUP BY 实现

(1)分组

(2)自动排序

2、无需排序:Order by NULL

3、特定排序:Group by DESC/ASC

4、举例

MySQL> select phone,count(*) from post group by phone limit 1 ;

1 row in set (2.19 sec)

MySQL> select phone,count(*) from post group by phone order by null limit 1;

1 row in set (2.02 sec)

28.同数据类型的列值比较

1、原则:数字对数字,字符对字符

2、数值列与字符类型比较

(1)同时转换为双精度

(2)进行比对

3、字符列与数值类型比较

(1)字符列整列转数值

(2)不会使用索引查询

4、举例:字符列与数值类型比较

字段:`remark` varchar(50) NOT NULL COMMENT '备注,

默认为空',

MySQL>SELECT `id`, `gift_code` FROM gift WHERE

`deal_id` = 640 AND remark=115127;

1 row in set (0.14 sec)

MySQL>SELECT `id`, `gift_code` FROM pool_gift WHERE

`deal_id` = 640 AND remark='115127';

1 row in set (0.005 sec)

29.Load data 导数据

1、批量数据快导入:

(1)成批装载比单行装载更快,不需要每次刷新缓存

(2)无索引时装载比索引装载更快

(3)Insert values ,values,values 减少索引刷新

(4)Load data比insert快约20倍

2、尽量不用 INSERT ... SELECT

(1)延迟

(2)同步出错

30.打散大批量更新

1、大批量更新凌晨操作,避开高峰

2、凌晨不限制

3、白天上限默认为100条/秒(特殊再议)

4、举例:

update post set tag=1 WHERE id in (1,2,3);

sleep 0.01;

update post set tag=1 WHERE id in (4,5,6);

sleep 0.01;

……

31.Know Every SQL

1、SHOW PROFILE

2、MySQLsla

3、MySQLdumpslow

4、EXPLAIN

5、Show Slow Log

6、Show Processlist

7、SHOW QUERY_RESPONSE_TIME(Percona)

五、约定类军规

32.隔离线上线下

1、构建数据库的生态环境

(1)开发无线上库操作权限

2、原则:线上连线上,线下连线下

(1)实时数据用real库

(2)模拟环境用sim库

(3)测试用qa库

(4)开发用dev库

33.禁止未经DBA确认的子查询

1、MySQL子查询

(1)大部分情况优化较差

(2)特别WHERE中使用IN id的子查询

(3)一般可用JOIN改写

反例:

MySQL> select * from table1 where id in (select id from table2);

MySQL> insert into table1 (select * from table2);

//可能导致复制异常

34.永远不在程序端显式加锁

1、永远不在程序端对数据库显式加锁

(1)外部锁对数据库不可控

(2)高并发时是灾难

(3)极难调试和排查

2、并发扣款等一致性问题

(1)采用事务

(2)相对值修改

(3)Commit前二次较验冲突

35.统一字符集为UTF8

1、字符集:

(1)MySQL 4.1 以前另有latin1

(2)为多语言支持增加多字符集

(3)也带来了N多问题

(4)保持简单

2、统一字符集:UTF8

3、校对规则:utf8_general_ci

4、乱码:SET NAMES UTF8

36.统一命名规范

1、库表等名称统一用小写

(1)Linux VS Windows

(2)MySQL库表大小写敏感

(3)字段名的大小写不敏感

2、索引命名默认为“idx_字段名”

3、库名用缩写,尽量在2~7个字母

(1)DataSharing ==> ds

4、注意避免用保留字命名

5、……

反例:Select * from return;

反例:Select * from `return`;

posted @ 2023-03-18 16:50  baivfhpwxf  阅读(34)  评论(0编辑  收藏  举报