当前位置 主页 > 行业资讯 >

    mysqlinsert,Load data比insert快约20倍

    栏目:行业资讯 时间:2021-03-05 16:31


    一、核心军规
         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`;