mysql
/* */ # 块注释-- # 行注释mysql -h127.0.0.1 -uroot -proot -p 2207 -D test # host user passwd port Database# basicSHOW CREATE TABLE xx; # 表结构DESC xx;CREATE TABLE yy LIKE xx; # 这样才能保持 表结构 + 索引INSERT yy SELECT * FROM xx ORDER BY col_xx; # 多进程插入时防死锁,主要 ORDER BY 字段要唯一,不然还是可能死锁ALTER TABLE xx ADD COLUMN xx_col bigint(20) NOT NULL DEFAULT 0 COMMENT 'xx' AFTER yy_col;ALTER TABLE xx MODIFY COLUMN xx_col bigint(20) NOT NULL DEFAULT 0 COMMENT 'xx' AFTER yy_col;ALTER TABLE xx DROP COLUMN xx_col;ALTER TABLE xx RENAME TO yy;# advancedINSERT IGNORE xx ON DUPLICATE KEY UPDATE # INSERT 要注意主键;IGNORE 重复时忽略;on duplicate key update 重复时更新SHOW PROCESSLIST; # 查看连接到 mysql 的进程EXPLAIN sql # sql 分析# functionconcat() # 其中一个为 null, 那么结果就是 null;拼接非字符串时, 需要配合 convert(num, char)# 自定义函数CREATE FUNCTION vipLevel (amount INT)RETURNS int(10)BEGIN DECLARE vip int(10); IF amount >=1000 THEN SET vip=2; ELSEIF amount>=600 THEN SET vip=1; ELSE SET vip=0; END IF; RETURN vip;END;-- unicode 转 utf-8:https://gist.github.com/joni/2956080DROP FUNCTION STRINGDECODE;CREATE FUNCTION STRINGDECODE(str TEXT CHARSET utf8)RETURNS text CHARSET utf8 DETERMINISTICBEGINdeclare pos int;declare escape char(6) charset utf8;declare unescape char(3) charset utf8;set pos = locate('\u', str);while pos > 0 do set escape = substring(str, pos, 5); set unescape = char(conv(substring(escape,2),16,10) using ucs2); set str = replace(str, escape, unescape); set pos = locate('\u', str, pos+1);end while;return str;END;SELECT STRINGDECODE("\u9648\u5fd7\u6797")# 导入、导出mysql -uroot -proot < /path/to/xxx.sql # 导入数据mysql> source /path/to/xxx.sqlmysqldump /*login*/ database > xxx.sql # 导出mysqldump /*login*/ database < xxx.sql # 导入if(col1=1,col1,0) as int_1 # 行列转换# mysql 允许外网访问bind-address # 修改 my.cnfupdate user set host='%' where user='root' # 修改 mysql.user 表GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'192.168.1.102' IDENTIFIED BY 'mypwd' WITH GRANT OPTION # 设定特定的连接flush privileges # 如果不执行这句, 需要重启 mysqld# 跳过密码验证登录skip-grant-tables # 修改 my.cnf, 被一个没有密码的登录账号给坑了好长时间mysql 的日常
- 如果有自增 id,多考虑使用自增 id,比如使用 id 查询最后几条数据
- 增删改应要当心,切记是否需要备份;能不删除尽量不删除,有种做法是表中添加
soft_delete字段标识记录是否删除 交换2列的值: join 一下自己
tinyint(1):表示一个字节, 数据范围是 0-255(unsigned), 所以用来表示数据类型完全够用, 基本不太可能会出现超出 255 种类型的枚举类型: 缺点很明显, 添加新字段的时候需要修改表结构, 所以建议使用
varchar()来替换, 当然如果程序写的不好, 添加新的类型的时候, 还是会很麻烦; 忽略大小写; 输入不在范围的值默认使用第一个如果数字的小数位数是固定的,可以考虑放大后使用 int 来存储,比如金额精确到分以元为单位就是固定 2 位小数
signed: 需要计算,并且结果可能为负数,大部分场景都是用unsignedsql执行时只能使用一个索引
索引最左原则: 只有最左边的元素出现在查询中, 索引才会被用到, 所以应该把 where 中使用最多的一列放到最左边
union all/or/in 的效率分析: 有索引时union all相对会快一点, 取决于索引查询的时间, 没有时都是全表扫描, all/or 要快一些
减少需要执行 sql 的数量, 尽量一次取出尽可能多的数据
like / regexp 效率: like 在左端不固定的场景下, 不会使用到索引, 所以我喜欢使用 regexp
orderby / groupby: sql 慢的时候考虑先 排序/分组, 再 join
优化:1. 减少sql数量, 一个sql取得多个需要的数据;2. 索引是否得当(explain 走起)
先修改 DB,再更新代码
修改线上库:确认是否需要备份、至少审核一遍 sql、本地可以测试一定要本地测试一遍
统计相关
- 需要合并多列数据到一行时,可以考虑
设置字段默认值 + unique key + insert + insert on duplicate update - mysql 按照 日、周、月 统计,周的周期从 周五-周四 group by DATE_FORMAT(DATE_ADD(created_time,INTERVAL 3 DAY),'%Y%u') -> 注意偏移量
- 按照人来去重,比如一个人下了 5 单,一单支付成功,转化率就是 100%,需要使用 case-when 将用户路径量化,然后 分组取最大值