选自:mysql笔记.pdf
mysql提供的help命令,对于我们只记得命令中的关键词,但是忘记了命令的具体的参数等情况下,非常有用。 例如:
help show; help create; help grant; help drop;还可以更进一步:我想创建一个新用户,只记得命令是’create user’开头的,但是忘记了后面一些具体参数,可以使用如下命令:
mysql> help create user;11表示的是显示宽度;select 查询结果显示时,如果数字没有11位,会用空格补齐11位;也可以用0补齐,需要将列定义为 int(11) unsigned zerofill,则对于33,会显示为00000000033; 对于int类型的列,如果没有定义显示宽度,则默认为11,因为int类型数据的最大值是11位的。
float 和 double 如果不设置精度和标度,则直接按实际精度存储和表示。
子句:where / order by / limit 等都是子句 clause:分句,指的是where子句中的查询条件分句:and分句,or分句等。 子查询:查询中嵌套了别的查询。
按子查询的结果集分为4种:
标量子查询,一行一列,单个结果列子查询,一列多行行子查询,一行多列表子查询,多列多行按照子查询的出现位置:
select后仅支持标量子查询from 后支持表子查询where / having 后,支持标量、行、列exists后,支持表子查询如:有一张购买记录表order,有三列分别为user_id, price,year;即用户id、价格、年份。 查找每个用户购买价格最高的记录,要有user_id,price,year。
select * from order where ( user_id,price ) in (select user_id,max(price) from order group by user_id)当where后的子查询是多列时(行或者表),必须用()将多列查询条件括起来。 当where后的子查询是多行时(列或者表),必须用in,或者用 = > < >= <= <> 与 any all some 合用 当where后的子查询是一行时(行或者标量),可以用= > < >= <= <> 与 。
又如: 有部门表departments,有列dep_id,dep_name; 有员工表employees,有列emp_id,emp_name,dep_id,salary; 有薪资等级表job_grades,有列grade_id,low,high 查询每个部门的员工个数:
select dep_name,(select count(emp_id) from employees e where e.dep_id=d.dep_id) from departments d;查询工号为’11’的员工的部门名称:
select dep_name from departments where dep_id=( select dep_id from employees e where e.emp_id='11'); 或 select dep_name from departments d join employees e on e.dep_id=d.dep_id and e.emp_id='11'; 或 select dep_name from departments d join employees e on e.dep_id=d.dep_id where e.emp_id='11';查询每个部门的平均薪资等级;
select dep_id,grad_id from (select dep_id, avg(salary) as s_avg from employees group by dep_id) a, job_grades g where s_avg>= g.low and s_avg<g.high对于null,只能用is null或者 is not null 来查询,其余运算符皆不可。
有表test1的数据如下:
c1c2111NULLNULLNULLselect * from test1 where c1 = NULL; —结果集为empty; select * from test1 where c1 != NULL; —结果集为empty; select * from test1 where c1 in ( NULL ) ; —结果集为empty; select * from test1 where c1 in ( NULL, 2 ) ; —结果集为empty; select * from test1 where c1 not in ( NULL ); —结果集为empty; select * from test1 where c1 not in ( NULL, 2 ); —结果集为empty;
atomicity:原子性,一个事务必须是一个原子操作。事务中的一批SQL语句要么全部成功地作用于数据库,要么全部不作用于数据库。可以参考java并发/多线程操作中的原子性问题(在java中有许多AtomicXXX类,利用了unsafe的CAS确保数据的原子性和一致性)
consistency:一致性,事务执行前,数据库中的数据在业务上是处于一致状态的;事务执行后,数据库中的数据在业务上是处于一致状态的。
isolation:隔离性,一个事务的执行不能被其它事务干扰。一个事务内部的操作及使用的数据对并发的其它数据是隔离的,并执行的各个事务之间不能
通过commit和rollback,来实现事务原子性。
通过事务的一致性视图和锁来实现事务隔离性
多版本并发控制(MultiVersion Concurrecy Control),支持这种机制的数据库被称为多版本数据库。
mysql中的一致性读操作分为快照读和当前读。快照读是通过MVCC实现,当前读通过加锁实现。快照读:读取的不一定是当前最新的数据,而是历史数据的其中一个快照。当前读:用于先读后写的操作,即读取到数据后会立即对数据更新。更新自然必须是要在最新数据上更新,如果对旧数据进行更新,就很有可能出现更新丢失等问题。当前读会对读到的数据加锁后,再进行更新操作。如果数据已经被其它事务加锁(即其它事务正在操作这些记录),那么此事务就必须等待直到获得数据的锁,才能对数据读取并更新。普通的select操作都是快照读。显式地select …lock in share mode / for update 是当前读。在事务中的update \ delete 等操作也都是当前读。当进行update或者delete\insert时,系统会给要更新的数据加锁,如果对数据加锁成功,则可以对数据进行读取并更新。如果数据已经被其它事务锁定,那就必须等待其它事务释放数据的锁。
myisam引擎本身并没有提供事务管理的功能。但是可以用lock tables t_name read | write,通过对表加锁来实现伪事务,隔离事务,实现安全的并发操作。
对于已经加了X锁的数据,虽然无法再加其它锁,但是仍可以对其做select操作,因为普通的select查询并不需要加锁。
行锁:在innodb中,查询条件上有索引时,单独的对某些索引加锁。没有索引时,就只能加表锁了,会造成冲突。注意是对索引加锁,不是对记录。因此如果一条索引下有多个记录,即便两个事务是要对同一个索引的不同记录加锁,仍然会有锁冲突。
间隙锁(gap-lock):间隙是指,当我们进行范围查询时,如果结果集有多行,则在范围内、相邻两行之间的不存在的记录被称为“间隙”。innodb也会对这个间隙加锁,就是间隙锁(next-key lock)。 另外在进行相等的当前查询并时,如果要查询的记录不存在,也会加间隙锁。 例如:一个session执行如下查询:begin; select id,name from t_user where user_id=101 for update。 如果这时另一个session 执行插入:insert into t_user values(201,…)。会等待
next-key lock:行锁和间隙锁的组合实现。
表锁:查询条件上没有索引时,锁全表。 lock table t1 read;–表共享锁。lock table t1 write;–表独占锁
如果某个间隙已经被事务加了间隙锁,并不会阻止其它事务对同一个间隙加间隙锁,只是会排斥其它事务向间隙中插入数据。
意向锁的是表级的,其目的是为了使得事务间的协调效率更高。 当一个事务需要对表加表独占锁时,首先要确保表没有被其它事务加了表共享锁、表独占锁、表也没有任何记录被加共享锁或者独占锁。 表共享锁、表独占锁标识都是打在表上的,很容易直接检测到是否已经被其它事务加锁。 但是对表中行的锁标记是打在了行上的,如果一行行去检查是否有行被加了锁,效率就很低了。 解决方案就是在给表中记录加上共享锁或者独占锁之前先给加个意向锁,相当于给表打个标记,标记此表中的记录会被加锁。 此时其它事务再加锁的话,就可以看到表上已经打了表级意向锁标识,不用再专门加锁了。
意向共享锁(IS,Intention-S); 是指事务打算给表中的数据加共享锁,事务在给数据加共享锁之前必须先取得表的IS锁。是Innodb自动加的,用户无法主动干预。意向排他锁(IX):是指事务打算给表中的数据加排他锁,事务在给数据加X锁之前,必须先取得表的IX锁。是Innodb自动加的,用户无法主动干预。显式地在sql语句中使用 lock in share mode时。会对符合条件的记录加意向共享锁。如果没有符合条件的记录,则会在小于条件的最大关键字和大于条件的最小关键字之间加间隙锁?
事务提交方式有两种:自动提交 和 手动提交。 隐式的事务提交方式:事务提交的默认方式,show variable like ‘%autocommit%’,一般是ON,即每条语句都会自动commit; 显式事务提交:如果隐式的事务提交方式状态不符合业务需求,可以通过set autocommit ON/OFF; 来设置后续语句的事务提交方式。
有时需要根据实际业务状况,对SQL语句做部分回退。 比如:
start transaction; sql1; savepoint s1; sql2; savepoint s2; sql3; savepoint s3; ... if(...) rollback to s1; --在某种情况下,业务状态需要回退到s1处,后续commit提交时,只会提交sql1。其后的语句都不会被提交至数据库。 if(...) rollback to s2; --在某种情况下,业务状态需要回退到s2处,后续commit提交时,只会提交sql1和sql2。其后的语句都不会被提交至数据库。 ... commit;系统变量前要用@@,自定义全局变量前要用@,自定义局部变量前什么也不用
enum
tinyint 1字节 smallint 2 midiumint 3 int 4 bigint 8
float 4 double 8 decimal(m,d) M+2
date 3(1000-01-01~9999-12-31) 15位(32768)-4位-5位 time 3(-838:59:59~838:59:59) 符号位2位?10位:6位:6位 year 1(1901~2155) 254 个值,8位即可。 datetime 8 timestamp 4(1970-01-01 00:00:00~2038-01-19 11:14:07) 1个符号位,2147483647个值,
char 1-255自定义;如果实际长度不足,则补足 varchar 1-255自定义:如果实际长度不足,不补,长度仅用作限定用。
tinyBlob(255个)blob(65535个)
select @@profilling; set @@profiling=1; show profiles; HELP SHOW PROFILE; show profile all ; show profile for query n;
tmp table --临时表
redo log只需确保未被刷回磁盘的事务被log即可。实现这一目的的方式是:redo log文件固定大小,当文件被写满后,就将缓存中的事务数据写入磁盘中去。是大小固定的、会被不断truncate的空间。 redo log在内存中也有缓存区,每秒会将缓冲区中的数据IO到磁盘。每当有事务提交时,也会将缓冲区中数据刷出到磁盘。 redo log的日志文件大小对mysql系统的影响: 设置较大值的情况下,顺序IO的重新寻道和旋转磁头的次数降低,可以大大提高顺序IO的性能。但是故障后恢复时,会由于redo log文件较大而增大数据恢复时间,在之前的mysql版本中,这会很慢,但是现在的版本不用再考虑这些问题,放心使用即可,
innodb_log_file_size:redo log 日志文件大小
binlog记录了所有操作的日志(除了select 和 show这类),即便操作目标行数为0。如果update …set … where …,即使根据查询条件没有匹配的记录,没有对任何记录进行update,也会被记录。 binlog是服务器层的功能。 binlog记录的是逻辑日志,是sql语句。redo log记录的是物理日志,是数据。 binlog只在一个事务提交完成后记录一条或几条sql语句。而redo log则是在事务进行中不断写入。 redo log的日志写入是并发的,多个事务进行中都在不断写入redo log.
mysql> help ana%; Name: ‘ANALYZE TABLE’ Description: Syntax: ANALYZE [NO_WRITE_TO_BINLOG | LOCAL] TABLE tbl_name [, tbl_name] …
rename as tbnewx;–重命名表名称 add column cname … firset | after column_name; --添加字段 add index idx_name(column1_name,…);–添加索引 add primary key(column_name);–添加主键 drop primary key; drop index idx_name; add unique idx_name(column1_name,…);–添加唯一索引 alter column column_name set default xx | drop default;–设置默认值,取消默认值 change column column_name column_name_new …;–重新定义某字段,可以重命名字段 modify column column_name …;–重新定义某字段,但不能重命名 drop column column_name;–删除某字段
create table tbx_new as select * from tbx;–复制表内容
show columns from tbx; show create table tbx;
select version(),connection_id(),database(),schema(),user(),system_user(),session_user(),current_user(),charset(str),last_insert_id();
password(‘pwd’),md5(‘xx’),encode(str,pswd_str)
curdate(),curr_date(),curtime(),current_time(),now(),current_timestamp(),localtime(),sysdate(),localtimestamp();