日常命令

  1. 链接远程数据库
1
2
mysql -h主机地址 -P端口 -u用户名 -p用户密码
mysql -h127.0.0.1 -P1234 -u"myname" -p"test123"
  1. 显示所有库
1
show databases;
  1. 进入数据库
1
use database_name;
  1. 显示当前库中所有的表
1
show tables;
  1. 显示表字段
1
desc table_name;
  1. 创建表
1
create table table_name (name char(100), path char(100), count int(10), firstName char(100), firstMD5 char(100), secondName char(100), secondMD5 char(100), thirdName char(100), thirdMD5 char(100));
  1. 修改表名
1
rename table table_name_old to table_name_new
  1. 插入数据
1
insert into table_name (name, path, count, firstName, firstMD5, secondName, secondMD5, thirdName, thirdMD5) VALUES ('test', 'test', 1, 'name1', 'md1', 'name2', 'md2', 'name3', 'md3');
  1. 查询表中数据
1
2
3
4
5
select * from table_name;

select * from table_name where name = 'test';

select * from table_name order by id limit 0,2;
  1. where、group by和having区别
1
2
3
4
5
6
7
8
9
// 1) 在SQL语句中,where子句并不是必须出现的
// 2) where子句是对检索记录中每一行记录的过滤
// 3) having子句出现在group by子句后面
// 4) 如果在一句SQL语句中,where子句和group by……having子句同时都有的话,必须where子句在前,group by……having子句在后。(where先执行,再groupby分组;groupby先分组,having再执行)
// 5) group by子句是对检索记录的分组,后面跟随的字段名是分组的依据。根据语法,在select子句中,除聚合函数语句外,SELECT子句中的每个列名称都必须在GROUP BY子句中作为分组的依据。


select vend_id, count(*) , sales from products group by vend_id;
这个语句,其中sales字段,在group by中没有,所以查询的结果,sales的值是错误的!
  1. 更新表中某一行数据
1
update table_name set folderName ='Mary' where id=1;
  1. 删除表中某一行数据
1
delete from table_name where folderName = 'test';
  1. 添加表字段
1
alter table table_name add id int auto_increment not null primary key;
  1. 删除字段
1
alter table table_name drop folderName;

left join、right join和inner join区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
表A
aID aNum
1 a1
2 a2
3 a3
4 a4
5 a5

表B
bID bNum
1 b1
2 b2
3 b3
4 b4
6 b6

left join

left join(左连接)返回包括左表中的所有记录和右表中联结字段相等记录。

1
2
3
4
5
6
7
8
select * from A left join B on A.aID = B.bID;

aID aNum bID bNum
1 a1 1 b1
2 a2 2 b2
3 a3 3 b3
4 a4 4 b4
5 a5 NULL NULL

left join是以A表的记录为基础的,A可以看成左表,B可以看成右表,left join是以左表为准的.
换句话说,左表(A)的记录将会全部表示出来,而右表(B)只会显示符合搜索条件的记录(例子中为: A.aID = B.bID), B表记录不足的地方均为NULL

right join

right join(右连接)返回包括右表中的所有记录和左表中联结字段相等记录。

1
2
3
4
5
6
7
8
select * from A right join B on A.aID = B.bID;

aID aNum bID bNum
1 a1 1 b1
2 a2 2 b2
3 a3 3 b3
4 a4 4 b4
NULL NULL 6 b6

仔细观察一下,就会发现,和left join的结果刚好相反,这次是以右表(B)为基础的,A表不足的地方用NULL填充.

inner join

inner join(等值连接)只返回两个表中联结字段相等行。

1
2
3
4
5
6
7
select * from A inner join B on A.aID = B.bID;

aID aNum bID bNum
1 a1 1 b1
2 a2 2 b2
3 a3 3 b3
4 a4 4 b4

很明显,这里只显示出了 A.aID = B.bID的记录.这说明inner join并不以谁为基础,它只显示符合条件的记录.

优化规则

核心

  1. 字段名不要使用‘key’ ‘index’ ‘like’‘time’ 等等关键字
  2. 表字段尽量少,上限控制在20~50个,适当可以冗余(平衡范式和冗余)。
  3. 不在数据库做强运算,不要使用存储过程、触发器等,数据库主要负责存储,不承担大量业务逻辑。
  4. 拒绝大sql,大事务。批量删除时,请控制在操作行数1万以内的小事务。批量插入时,请控制并发,并发搞很容易死锁。

索引

  1. 能不加的索引尽量不加,最好不超过字段数的20%(如:性别不加),结合核心SQL优先考虑覆盖索引(https://my.oschina.net/BearCatYN/blog/476748)
  2. 字符字段必须建前缀索引。由于字符串很长,通常可以索引开始的几个字符,而不是全部值,以节约空间并得到好的性能。(http://www.educity.cn/wenda/402373.html)
  3. 不在索引列进行数学运算和函数运算(会导致无法使用索引 => 全表扫描),如where id+1 = 100 和 id = 100 - 1,效率差很远
  4. 自增列或全局ID做INNODB的主键
  5. 尽量不用外键(由程序保证约束),高并发的时候容易死锁。

sql语句

  1. 尽量少用select *,只取需要数据列,为使用覆盖索引提供可能性,减少临时表生成,更安全
  2. 用in()代替or,因为or的效率是O(n),而in()的效率是O(Log n)。如:where a = 1 OR a = 100 与 where a IN (1, 100)
  3. 尽量避免负向查找,如NOT、!=等
  4. 减少COUNT(*),使用COUNT(col),前者资源开销大,尽量少用。
  5. 大批量更新凌晨操作,避开高峰,零点附近往往定时任务量比较大,如果可以,尽量安排在03:00-07:00.
  6. LIMIT高效分页:传统的方法是select from t limit 10000, 10,推荐的方法是select from t where id > 23423 limit 10。LIMIT的偏移量越大则越慢。还有一些高效的方法有:先取id来LIMIT偏移,减少整体的数据偏移;取到需要的id,与原表JOIN;程序取ID,然后用IN来填写。select from t where id >= (select id from t limit 10000, 1) limit 10 , select from t INNER JOIN (select id from t limit 10000, 10) USING (id) , select id from t limit 10000, 10; select * from t where id in (123, 456…)
  7. 尽量避免%前缀模糊查询,由于使用的是B+ Tree,前缀模糊使用不了索引,导致全表扫描(后缀模糊速度相对快很多)

优化总结

  1. SQL语句优化,尽量精简,去除非必要语句
  2. 索引优化,让所有SQL都能够走索引
  3. 如果是表的瓶颈问题,则分表,单表数据量维持在1000W以内
  4. 如果是单库瓶颈问题,则分库,读写分离
  5. 如果是物理机器性能问题,则分多个数据库节点

mysql执行过程


绿色部分为SQL实际执行部分,主要分为两步:

解析:词法解析->语法解析->逻辑计划->查询优化->物理执行计划,过程中会检查缓存是否可用,如果没有可用缓存则进入下一步mysql_execute_command执行

执行:检查用户、表权限->表加上共享读锁->取数据到query_cache->取消共享读锁