它和DML语句最大的区别是DML只是对表内部数据操做,而不涉及表的定义、结构的修改,更不会涉及其余对象。mysql
CREATE DATABASE dbname
复制代码
DROP DATABASE dbname
复制代码
CREATE TABLE tablename (
column_name_1 column_type_1 constraints,
column_name_2 column_type_2 constraints,
...
column_name_n column_type_n constraints)
复制代码
MySQL的表名是以目录的形式存在于磁盘上的,因此表名的字符能够用任何目录名容许的字符。算法
DROP TALBE tablename
复制代码
-- 修改表类型
ALTER TABLE tablename MODIFY [COLUMN] column_definition [FIRST|AFTER col_name]
-- 增长表字段
ALTER TABLE tablename ADD [COLUMN] column_definition [FIRST|AFTER col_name]
-- 删除表字段
ALTER TABLE tablename DROP [COLUMN] col_name
-- 字段更名
ALTER TALBE tablename CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST|AFTER col_name]
-- 更改表名
ALTER TABLE tablename RENAME [TO] new_tablename
复制代码
注意:sql
INSERT INTO tablename(field1,field2,...,fieldn) VALUES(value1,value2,...,valuen)
复制代码
UPDATE tablename SET field1=value1,field2=value2,...,fieldn=valuen [WHERE CONDITION]
复制代码
DELETE FROM tablename [WHERE CONDITION]
复制代码
在MySQL中能够一次删除多个表的数据,语法以下:shell
DELETE t1,t2,...,tn FROM t1,t2,...,tn [WHERE CONDITION]
复制代码
若是from后面的表名用别名,则delete后面也要用相应的别名,不然会提示语法错误。数据库
-- 排序
SELETE * FROM tablename [WHERE CONDITION] [ORDER BY field1 [DESC|ASC], field2 [DESC|ASC],...,fieldn [DESC|ASC]]
-- 限制
SELECT ... [LIMIT offset_start,row_count]
-- 聚合
SELECT [field1,field2,...,fieldn] fun_name FROM tablename [WHERE where_condition] [GROUP BY field1,field2,...,fieldn] [WITH ROLLUP] [HAVING having_condition]
复制代码
注意:缓存
DCL语句主要是DBA用来管理系统中的对象权限时使用,通常的开发人员不多使用。如下经过例子说明。安全
-- 建立一个数据库用户z1,具备对sakila数据库中全部表的SELECT/INSERT权限
GRANT select,insert ON sakila.* to 'z1'@'localhost' identified by '123';
-- 收回INSERT权限
REVOKE insert ON sakila.* FROM 'z1'@'localhost';
复制代码
整数类型 | 字节 | 最小值 | 最大值 |
---|---|---|---|
TINYINT | 1 | 有符号 -128 无符号 0 |
有符号 127 无符号 255 |
SMALLINT | 2 | 有符号 -32768 无符号 0 |
有符号 32767 无符号 65535 |
MEDIUMINT | 3 | 有符号 -8388608 无符号 0 |
有符号 8388607 无符号 1677215 |
INT、INTEGER | 4 | 有符号 -2147483648 无符号 0 |
有符号 2147483647 无符号 4294967295 |
BIGINT | 8 | 有符号 -9223372036854775808 无符号 0 |
有符号 9223372036854775807 无符号 18446744073709551615 |
浮点类型 | 字节 | 最小值 | 最大值 |
FLOAT | 4 | ±1.175494351E-38 | ±3.402823466E+38 |
DOUBLE | 8 | ±2.2250738585072014E-308 | ±1.7976931348623157E+308 |
位类型 | 字节 | 最小值 | 最大值 |
BIT(M) | 1~8 | BIT(1) | BIT(64) |
定点类型 | 字节 | 描述 |
---|---|---|
DEC(M,D), DECIMAL(M,D) |
M+2 | 最大值范围与DOUBLE相同,给定DECIMAL的有效取值范围由M和D决定 |
对于整型数据,MySQL还支持在类型名称后面的小括号内指定显示宽度,例如int(5)表示当数值宽度小于5位的时候在数字前面填满宽度,若是不显示指定宽度则默认为int(11)。通常配合zerofill使用,顾名思义,zerofill就是用"0"填充的意思,也就是在数字位数不够的空间用字符"0"填充。bash
若是一列指定为zerofill,则MySQL自动为该列添加UNSIGNED属性。服务器
日期时间类型 | 字节 | 最小值 | 最大值 |
---|---|---|---|
DATE | 4 | 1000-01-01 | 9999-12-31 |
DATETIME | 8 | 1000-01-01 00:00:00 | 9999-12-31 23:59:59 |
TIMESTAMP | 4 | 19700101080001 | 2038年的某个时刻 |
TIME | 3 | -838:59:59 | 838:59:59 |
YEAR | 1 | 1901 | 2155 |
TIMESTAMP有一个重要的特色,就是和时区相关。当插入日期时,会先转换为本地时区后存放;而从数据库里面取出来时,也一样须要将日期转换为本地时区后显示。session
字符串类型 | 字节 | 描述及存储需求 |
---|---|---|
CHAR(M) | M | M为0~255之间的整数 |
VARCHAR(M) | M为0~65535之间的整数,值的长度为+1字节 | |
TINYBLOB | 容许长度0~255字节,值的长度+1字节 | |
BLOB | 容许长度0~65535字节,值的长度+2字节 | |
MEDIUMBLOB | 容许长度0~167772150字节,值的长度+3字节 | |
LONGBLOB | 容许长度0~4394967295字节,值的长度+4字节 | |
TINYTEXT | 容许长度0~255字节,值的长度+2字节 | |
TEXT | 容许长度0~65535字节,值的长度+3字节 | |
MEDIUMTEXT | 容许长度0~167772150字节,值的长度+3字节 | |
LONGTEXT | 容许长度0~4394967295字节,值的长度+4字节 | |
VARBINARY(M) | 容许长度0~M字节的变长字节字符串,值的长度+1个字节 | |
BINARY(M) | M | 容许长度0~M字节的变长字节字符串 |
在检索的时候,CHAR列删除了尾部的空格,而VARCHAR则保留这些空格。
它的值范围须要在建立表时经过枚举方式显式指定,对1~255个成员的枚举须要1个字节存储;对于255~65535个成员,须要2个字节存储。最多容许有65535个成员。
SET和ENUM类型很是相似,也是一个字符串对象,里面能够包含0~64个成员。
SET和ENUM除了存储以外,最主要的区别在于SET类型一次能够选取多个成员,而ENUM则只能选一个。
函数 | 功能 |
---|---|
CONCAT(S1,S2,...,Sn) | 字符串链接 |
INSERT(str,x,y,instr) | 将字符串str从第x位置开始,y个字符长的子串替换为字符串instr |
LOWER(str) | 转小写 |
UPPER(str) | 转大写 |
LEFT(str,x) | 返回字符串str最左边的x个字符 |
RIGHT(str,x) | 返回字符串str最右边的x个字符 |
LPAD(str,n,pad) | 用字符串pad对str最左边进行填充,知道长度为n个字符长度 |
RPAD(str,n,pad) | 用字符串pad对str最右边进行填充,知道长度为n个字符长度 |
LTRIM(str) | 去掉字符串str左侧的空格 |
RTRIM(str) | 去掉字符串str右侧的空格 |
REPEAT(str,x) | 返回str重复x次的结果 |
REPLACE(str,a,b) | 用字符串b替换字符串str中全部出现的字符串a |
STRCMP(s1,s2) | 比较字符串s1和s2 |
TRIM(str) | 去掉字符串行尾和行头的空格 |
SUBSTRING(str,x,y) | 返回从字符串str x位置起y个字符长度的字串 |
函数 | 功能 |
---|---|
ABS(x) | 绝对值 |
CEIL(x) | 返回大于x的最小整数 |
FLOOR(x) | 返回小于x的最大整数 |
MOD(x,y) | 返回x/y的模 |
RAND() | 返回0~1内的随机值 |
ROUND(x,y) | 返回参数x的四舍五入的有y位小数的值 |
TRUNCATE(x,y) | 返回数字x截断为y位小数的结果 |
函数 | 功能 |
---|---|
CURDATE() | 返回当前日期 |
CURTIME() | 返回当前时间 |
NOW() | 返回当前的日期和时间 |
UNIX_TIMESTAMP(date) | 返回日期date的UNIX时间戳 |
FROM_UNIXTIME | 返回UNIX时间戳的日期值 |
WEEK(date) | 返回日期date为一年中的第几周 |
YEAR(date) | 返回日期date的年份 |
HOUR(time) | 返回time的小时值 |
MINUTE(time) | 返回time的分钟值 |
MONTHNAME(date) | 返回date的月份名 |
DATE_FORMAT(date,fmt) | 返回按字符串fmt格式化日期date值 |
DATE_ADD(date,INTERVAL expr type) | 返回一个日期或时间值加上一个时间间隔的时间值 |
DATEDIFF(expr,expr2) | 返回起始时间expr和结束时间expr2之间的天数 |
函数 | 功能 |
---|---|
IF(value,t,f) | 若是value为真,返回t,不然返回f |
IFNULL(value1,value2) | 若是value1不为空,则返回value1,不然返回value2 |
CASE WHEN [value1] THEN [result1]...ELSE [default] END | 若是value1是真,返回result1,不然返回default |
CASE [expr] WHEN [value1] THEN [result1]...ELSE [default] END | 若是expr等于value1,返回result,不然返回default |
函数 | 功能 |
---|---|
DATABASE() | 返回当前数据库名 |
VAERSION() | 当前数据库版本 |
USER() | 当前登陆用户名 |
INET_ATON(IP) | 返回IP地址的数字表示 |
INET_NTOA(mum) | 返回数字表示的IP地址 |
PASSWORD(str) | 返回字符串str的加密版本 |
MD5() | 返回字符串str的MD5值 |
MySQL5.0支持的存储引擎包括MyISAM、InnoDB、BDB、MEMORY、MERGE、EXAMPLE、NDB Cluster、ARCHIVE、CSV、BLACKHOLE、FEDERATED等,其中InnoDB和BDB提供事务安全表,其余存储引擎都是非事务安全表。
查看当前默认存储引擎,可使用以下命令。
show varivales like 'table_type';
复制代码
查询当前数据库支持的存储引擎,可使用如下两种方式。
SHOW ENGINES\G;
SHOW VARIABLES LIKE 'have%';
复制代码
特色 | MyISAM | InnoDB | MEMORY | MERGE | NDB |
---|---|---|---|---|---|
存储限制 | 有 | 64TB | 有 | 没有 | 有 |
事务安全 | 支持 | ||||
锁机制 | 表锁 | 行锁 | 表锁 | 表锁 | 行锁 |
B树索引 | 支持 | 支持 | 支持 | 支持 | 支持 |
哈希索引 | 支持 | 支持 | |||
全文索引 | 支持 | ||||
集群索引 | 支持 | ||||
数据缓存 | 支持 | 支持 | 支持 | ||
索引缓存 | 支持 | 支持 | 支持 | 支持 | 支持 |
数据可压缩 | 支持 | ||||
空间使用 | 低 | 高 | N/A | 低 | 低 |
内存使用 | 低 | 高 | 中等 | 低 | 高 |
批量插入的速度 | 高 | 低 | 高 | 高 | 高 |
支持外键 | 支持 |
MyISAM不支持事务、也不支持外键,其优点是访问的速度快,对事务完整性没有要求或者以SELECT、INSERT为主的应用基本上均可以使用这个引擎来建立表。
每一个MyISAM在磁盘上存储成3个文件,其文件名都和表名相同,但扩展名分别是:
数据文件和索引文件能够放置在不一样的目录,平均分布IO,得到更快的速度。
InnoDB存储引擎提供了具备提交、回滚和崩溃回复能力的事务安全。
能够经过ALTER TABLE *** AUTO_INCREMENT = n;
语句强制设置自动增加列的初始值,默认从1开始,可是该强制的默认值是保留在内存中的,若是该值在使用以前数据库从新启动,那么这个强制的默认值就会丢失,就须要在数据库启动之后从新设置。
对于InnoDB,自动增加列必须是索引。若是是组合索引,也必须是组合索引的第一列,可是对于MyISAM表,自动增加列能够是组合索引的其余列,这样插入记录后,自动增加列是按照组合索引的前面几列进行排序后递增的。
MySQL支持外键的存储引擎只有InnoDB,在建立外键的时候,要求父表必须有对应的索引,子表在建立外键的时候也会自动建立对应的索引。
CREATE TABLE country(
country_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
country VARCHAR(50) NOT NULL,
last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (country_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE city(
city_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
city VARCHAR(50) NOT NULL,
country_id SMALL UNSIGNED NOT NULL,
last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (city_id),
KEY idx_fk_country_id (country_id),
CONSTRAINT 'fk_city_country' FOREIGN KEY (country_id) REFERENCES country(country_id) ON DELETE RESTRICT ON UPDATE CASCADE
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
复制代码
能够指定在删除、更新父表时,对子表进行的相应操做,包括RESTRICT、CASCADE、SET NULL和NO ACTION。其中RESTRICT和NO ACTION相同,是指限制在子表有关联记录的状况下父表不能更新;CASCADE表示父表在更新或者删除时,更新或者删除子表对应记录;SET NULL则表示父表在更新或者删除的时候,子表的对应字段被SET NULL。
InnoDB存储表和索引有如下两种方式。
MEMORY存储引擎使用存在于内存中的内容建立表。每一个MEMORY表只实际对应一个磁盘文件,格式是.frm。MEMORY类型的表访问很是快,由于它的数据是放在内存中的,而且默认使用HASH索引,可是一旦服务关闭,表中的数据就会丢失掉.
MERGE存储引擎是一组MyISAM组合,这些MyISAM表必须结构彻底相同,MERGE表自己并无数据,对MERGE类型的表能够进行查询、更新、删除操做,这些操做其实是对内部的MyISAM表进行的。
MERGE表在磁盘上保留两个文件,文件名以表的名字开始,一个.frm文件存储表定义,另外一个.MRG文件包含组合表的信息,包括MERGE表由哪些表组成、插入新的数据时的依据。
查看全部可用的字符集的命令是show character set;
或者查看information_schema.character_set,可用显示全部的字符集和该字符集默认的校对规则。
MySQL的字符集和校对规则有4个级别的默认设置:服务器级、数据库级、表级和字段级。
能够在my.cnf中设置
[mysqld]
character-set-server=gbk
复制代码
或者在启动选项中指定
mysqld --character-set-server=gbk
复制代码
或者在编译时指定
shell> cmake . -DEFALUT_CHARSET=gbk
复制代码
可使用show variables like 'character_set_server'
命令查询当前服务器的字符集和校对规则。
show variables like 'character_set_server';
show variables like 'collation_server';
复制代码
数据库的字符集和校对规则在建立数据库的时候指定,也能够再建立完数据库后经过alter database
命令进行修改。须要注意的是,若是数据库里已经存在数据,由于修改字符集并不能将已有的数据按照新的字符集进行存放,因此不能经过修改数据库的字符集直接修改数据的内容。
要显示当前数据库的字符集和校对规则,可使用show variables like 'character_set_database'
和show variables like 'collation_database'
命令查看。
show variables like 'character_set_database';
show variables like 'collation_database';
复制代码
表的字符集和校对规则在建立表的时候指定,能够经过alter table命令进行修改,一样,若是表中已有记录,修改字符集对原有的记录并无影响,不会按照新的字符集进行存放。表的字段仍然使用原来的字符集。
要显示表的字符集和校对规则,可使用show create table
命令查看。
show create table z1\G;
复制代码
MySQL能够定义列级别的字符集和校对规则,主要是针对相同的表不一样字段须要使用不一样的字符集的状况,应该说通常遇到这种状况的概率比较小,这只是MySQL提供给咱们一个灵活设置的手段。
对于客户端和服务器的交互操做,MySQL提供了3中不一样的参数:character_set_client、character_set_connection和character_set_results,分别表明客户端、链接和返回结果的字符集。一般状况下,这3个字符集应该是相同的,才能够确保用户写入的数据能够正确地读出。
一般状况下,不会单个设置这3个参数,能够经过如下命令:
SET NAMES ***
复制代码
这个命令能够同时修改这3个参数的值。使用这个方法修改链接的字符集和校对规则,须要应用每次链接数据库后都执行这个命令。
另外一个更简便的方法,是在my.cnf中设置如下语句:
[mysql]
default-character-set=gbk
复制代码
(1) 导出表结构
mysqldump -uroot -p --default-character-set=gbk -d databasename > create.sql
复制代码
其中--default-character-set=gbk表示设置以什么字符集链接,-d表示只导出表结构,不导出数据。
(2) 手工修改create.sql中表结构定义中的字符集为新的字符集。
(3) 确保记录再也不更新,导出全部记录。
msyqldump -uroot -p --quick --no-create-info --extended-insert --default-character-set=latin1 databasename > data.sql
复制代码
(4) 打开data.sql,将SET NAMES latin1修改为SET NAMES gbk。
(5) 使用新的字符集建立新的数据库
create database databasename default charset gbk;
复制代码
(6) 建立表,执行create.sql
mysql -uroot -p databasename < craete.sql
复制代码
(7) 导入数据,执行data.sql
mysql -uroot -p databasename < data.sql
复制代码
MyISAM和InnoDB存储引擎的表默认建立的都是BTREE索引。MySQL目前还不支持函数索引,可是支持前缀索引,即对索引的前N个字符建立索引。前缀索引的长度跟存储引擎相关,对于MyISAM存储引擎的表,索引的前缀长度能够达到1000字节长,而对于InnoDB存储引擎的表,索引的前缀长度最长是767字节。请注意前缀的限制应以字节为单位进行测量,而CREATE TABLE语句中的前缀长度解释为字符数。
建立索引的语法
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [USING index_type]
ON table_name (index_col_name,...)
index_col_name: col_name [(length)] [ASC|DESC]
复制代码
索引的删除语法为
DROP IDNEX index_name ON tab_namne
复制代码
HASH索引有一些重要的特征须要在使用的时候特别注意,以下所示。
而对于BTREE索引,当使用>、<、>=、<=、BETWEEN、!=或者<>,或者LIKE 'pattern'(其中'pattern'不以通配符开始)操做符时,均可以使用相关列上的索引。
视图(View)是一种虚拟存在的表,对于使用视图的用户来讲基本上是透明的。
建立视图须要有CREATE VIEW的权限,而且对于查询涉及的列有SELECT权限。若是使用CREATE OR REPLACE或者ALTER修改视图,那么还须要该视图的DROP权限。
-- 建立视图
CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED|MERGE|TEMPTABLE}]
VIEW view_name [(column_list)]
AS select_statement
[WITH[CASCADED|LOCAL]CHECK OPTION]
-- 修改视图
ALTER [ALGORITHM={UNDEFINED|MERGE|TEMPTABLE}]
VIEW view_name [(column_list)]
AS select_statement
[WITH[CASCADED|LOCAL]CHECK OPTION]
复制代码
视图的可更改性和视图中查询的定义有关系,如下类型的视图是不可更新的。
用户能够一次删除一个或者多个视图,前提是必须有该视图的DROP权限。
DROP VIEW [IF EXISTS] view_name[,view_name]...[RESTRICT|CASCADE]
复制代码
从MySQL5.1版本开始,使用SHOW TABLES命令的时候不只显示表的名字,同时也会显示视图的名字。
SHOW TABLES
复制代码
一样,在使用SHOW TABLES STATUS命令的时候,不但能够显示表的信息,同时也能够显示视图的信息。
SHOW TABLES STATUS [FROM db_name] [LIKE 'pattern']
复制代码
存储过程和函数是事先通过编译并存储在数据库中的一段SQL语句的集合。
存储过程和函数的区别在于函数必须有返回值,而存储过程没有,存储过程的参数可使用IN、OUT、INOUT类型,而函数的参数只能是IN类型的。
LOCK TABLES 能够锁定用于当前线程的表。若是表被其余线程锁定,则当前线程会等待,直到能够获取全部锁定位置。
UNLOCK TALBES能够释放当前线程得到的任何锁定。当前线程执行另外一个LOCK TABLES时,或当服务器的链接被关闭时,全部由当前线程锁定的表被隐含地解锁。
LOCK TABLES
tal_name [AS alias] {READ[LOCAL]|[LOW_PRIORITY] WRITE}
[,tal_name [AS alias] {READ[LOCAL]|[LOW_PRIORITY] WRITE}]...
UNLOCK TABLES
复制代码
MySQL经过SET AUTOCOMMIT、START TRANSACTION、COMMIT和ROLLBACK等语句支持本地事务,具体语法以下:
START TRANSACTION | BEGIN [WORK]
COMMIT [WORK] [AND [NO] CHAIN][[NO] RELEASE]
ROLLBACK [WORK] [AND [NO] CHAIN][[NO] RELEASE]
SET AUTOCOMMIT={0|1}
复制代码
默认状况下,MySQL是自动提交(AutoCommit)的,若是须要经过明确的Commit喝Rollback来提交和回滚事务,那么就须要经过明确的事务控制命令来开始事务,这是和Oracle事务管理明显不一样的地方。
在锁表期间,用 START TRANSACTION命令开始一个新事务,会形成一个隐含地UNLOCK TABLES被执行。
分区引入了分区键(partition key)的概念,分区键用来根据某个区间值(或者范围值)、特定值列表或者HASH函数值执行数据的汇集,让数据根据规则分布在不一样的分区中,让一个大对象变成一些小对象。
能够经过SHOW VARIABLES
命令来肯定当前的MySQL是否支持分区
SHOW VARIABLES LIEK '%partition%'
复制代码
在MySQL5.1中可用的分区类型,主要有如下4种。
在MySQL5.1版本中,RANGE分区、LIST分区、HASH分区都要求分区键必须是INT类型,或者经过表达式返回INT类型。不管哪一种MySQL分区类型,不能使用主键/惟一键字段以外的其余字段分区。
CREATE TABLE emp(
id INT NOT NULL,
store_id INT NOT NULL
)PARTITION BY RANGE(store_id)(
PARTITION p0 VALUES LESS THEN (10),
PARTITION p1 VALUES LESS THEN (20),
PARTITION p2 VALUES LESS THEN (30)
);
复制代码
CREATE TABLE expenses(
expense_date DATE NOT NULL,
category INT
)PARTITION BY LIST(category)(
PARTITION p0 VALUES IN(3, 5),
PARTITION p1 VALUES IN(1, 10),
PARTITION p2 VALUES IN(4, 9),
PARTITION p3 VALUES IN(2),
PARTITION p4 VALUES IN(6)
);
复制代码
Columns分区是MySQL5.5引入的分区类型,引入Columns分区解决了MySQL5.5版本以前RANGE分区和LIST分区只支持整型分区,从而致使须要额外的函数计算获得整数或经过额外的转换表来转换为整数再分区的问题。Columns分区能够细分为RANGE Columns分区和LIST Columns分区,RANGE Columns分区和LIST Columns分区都支持整数、日期时间、字符串三大数据类型。
对比RANGE分区和LIST分区,Columns分区的亮点除了支持数据类型增长以外,另外,一大亮点是Columns分区还支持多列分区。
CREATE TABLE r3(
a INT,
b INT
)PARTITION BY RANGE COLUMNS(a, b)(
PARTITION p01 VALUES LESS THAN (0, 10),
PARTITION p02 VALUES LESS THAN (10, 10),
PARTITION p03 VALUES LESS THAN (10, 20),
PARTITION p04 VALUES LESS THAN (10, 35),
PARTITION p05 VALUES LESS THAN (10, MAXVALUE),
PARTITION p06 VALUES LESS THAN (MAXVALUE, MAXVALUE)
);
复制代码
HASH分区主要用来分散热点读,确保数据在预先肯定个数的分区中尽量平均分布。
MySQL支持两种HASH分区,常规HASH分区和线性HASH分区;常规HASH使用的是取模算法,线性HASH分区使用的是一个线性的2的幂的运算法则。
-- 常规HASH分区
CREATE TABLE emp(
id INT NOT NULL,
store_id INT NOT NULL
)PARTITION BY HASH(store_id) PARTITIONS 4;
-- 线性HASH
CREATE TABLE emp(
id INT NOT NULL,
store_id INT NOT NULL
)PARTITION BY LINEAR HASH(store_id) PARTITIONS 4;
复制代码
按照Key进行分区很是相似于按照HASH进行分区,只不过HASH分区容许使用用户自定义的表达式,而Key分区不容许使用用户自定义的表达式,须要使用MySQL服务器提供的HASH函数;同时HASH分区只支持整数分区,而Key分区支持使用除BLOB或Text类型外其余类型的列做为分区键。
CREATE TABLE emp(
id INT NOT NULL,
store_id INT NOT NULL,
job VARCHAR(30) NOT NULL
)PARTITION BY KEY (job) PARTITIONS 4;
复制代码
建立Key分区表的时候,能够不指定分区键,默认会首先选择使用主键做为分区键,在没有主键的状况,会选择非空惟一键做为分区键。
MySQL不由止在分区键值上使用NULL,分区键多是一个字段或者一个用户定义的表达式。通常状况下,MySQL的分区把NULL当作零值,或者是一个最小值进行处理。
注意:RANGE分区中,NULL值会被看成最小值来处理;LIST分区中,NULL值必须出如今枚举列表中,不然不被接受;HASH/KEY分区中,NULL值会被看成零值来处理。
show [session|global] status
复制代码
下面的命令显示了当前session中全部统计参数的值:
mysql> show status like 'Com_%';
+-------------------------------------+-------+
| Variable_name | Value |
+-------------------------------------+-------+
| Com_admin_commands | 0 |
| Com_assign_to_keycache | 0 |
| Com_alter_db | 0 |
| Com_alter_event | 0 |
| Com_alter_function | 0 |
| Com_alter_instance | 0 |
| Com_alter_procedure | 0 |
| Com_alter_resource_group | 0 |
| Com_alter_server | 0 |
| Com_alter_table | 0 |
| Com_alter_tablespace | 0 |
| Com_alter_user | 0 |
| Com_alter_user_default_role | 0 |
| Com_analyze | 0 |
| Com_begin | 0 |
| Com_binlog | 0 |
| Com_call_procedure | 0 |
| Com_change_db | 1 |
| Com_change_master | 0 |
| Com_change_repl_filter | 0 |
| Com_check | 0 |
...
复制代码
Com_xxx表示每一个xxx语句执行的次数,一般比较关心的是如下几个统计参数:
上面这些参数对于全部存储引擎的表操做都会进行累加。下面这几个参数只是针对InnoDB存储引擎的,累加的算法也略有不一样。
经过以上几个参数,能够很容易地了解当前数据库是以插入更新为主仍是以查询操做为主。
对于事务型的应用,能够经过Com_commit
和Com_rollback
能够了解事务和回滚的状况。
经过如下几个参数能够了解数据库的基本状况:
MySQL4.1开始引入explain extended
命令,经过explain extended
加上show warnings
,可以看到SQL真正被执行以前优化器作了哪些SQL改写。
MySQL5.1开始支持分区功能,同时explain命令也增长了对分区的支持。能够经过explain partitions
命令查看SQL所访问的分区。
经过have_profiling参数,查看当前MySQL是否支持profile。
select @@have_profiling;
+------------------+
| @@have_profiling |
+------------------+
| YES |
+------------------+
复制代码
默认profiling是关闭的,能够经过set语句在session级别开启profiling:
select @@profiling;
+-------------+
| @@profiling |
+-------------+
| 0 |
+-------------+
set profiling = 1;
复制代码
经过show profiles语句,查看执行SQL的Query ID
show profiles;
+----------+----------+-----------------------------+
| Query_ID | Duration | Query |
+----------+----------+-----------------------------+
| 1 | 8.7e-05 | SHOW WARNINGS |
| 2 | 0.000141 | select @@profiling |
| 3 | 6.8e-05 | SHOW WARNINGS |
| 4 | 0.000324 | select * from customer_part |
| 5 | 5.2e-05 | SHOW WARNINGS |
| 6 | 4.4e-05 | SHOW WARNINGS |
| 7 | 0.000199 | select @@have_profiling |
| 8 | 7.5e-05 | SHOW WARNINGS |
+----------+----------+-----------------------------+
复制代码
经过show profile for query {queryId}语句可以看到执行过程当中线程的每一个状态和消耗时间
show profile for query 4;
+--------------------------------+----------+
| Status | Duration |
+--------------------------------+----------+
| starting | 0.000077 |
| Executing hook on transaction | 0.000009 |
| starting | 0.000008 |
| checking permissions | 0.000006 |
| Opening tables | 0.000033 |
| init | 0.000006 |
| System lock | 0.000009 |
| optimizing | 0.000005 |
| statistics | 0.000013 |
| preparing | 0.000014 |
| executing | 0.000052 |
| end | 0.000005 |
| query end | 0.000003 |
| waiting for handler commit | 0.000008 |
| closing tables | 0.000008 |
| freeing items | 0.000024 |
| cleaning up | 0.000044 |
+--------------------------------+----------+
复制代码
MySQL支持进一步选择all、cpu、block io、context、switch、page faults等明细类型来查看MySQL在使用什么资源上耗费了太高的时间
show profile cpu for query 1;
复制代码
MySQL5.6提供了对SQL跟踪trace。
使用方式:首先打开trace,设置格式为JSON,设置trace最大可以使用的内存大小,避免解析过程当中由于默认内存太小而不可以完整显示。
SET OPTIMIZER_TRACE="enabled=on",END_MARKERS_IN_JSON=on;
SET OPTIMIZER_TRACE_MAX_MEM_SIZE=1000000;
复制代码
接下来执行想要trace的SQL语句
select rental_id from rental where rental_date >= '2005-05-25 04:00:00' and rental_date <= '2005-05-25 05:00:00' and inventory_id = 5566;
复制代码
最后检查INFORMATION_SCHEMA.OPTIMIZER_TRACE就能够知道MySQL是如何执行SQL的
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\G;
复制代码
索引是在MySQL的存储引擎层中实现的,而不是在服务器层实现的。MySQL目前提供如下4种索引:
前缀索引也有缺点,在排序Order By和分组Group By操做的时候没法使用。
若是索引正在工做,Handler_read_key的值将很高,这个值表明了一个行被索引值读的次数,很低的值代表增长索引获得的性能改善不高,由于索引并不常用。
Handler_read_rnd_next的值高则意味着查询运行低效,而且应该创建索引补救。这个值的含义是在数据文件中读下一行的请求数。
show status like 'Handler_read%';
复制代码
按期分析表和检查表
-- 分析表
ANLYZE [LOCAL|NO_WRITE_TO_BINLOG] TALBE tbl_name[,tbl_name]...
-- 检查表
CHECK TALBE tbl_name[,tbl_name]...[option]...option={QUICK|FAST|MEDIUM|EXTENDED|CHANGED}
复制代码
在分析期间,使用一个读取锁定对表进行锁定。
按期优化表
OPTIMIZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE tbl_name[,tbl_name]...
复制代码
若是已经删除了表的一大部分,或者若是已经对含有可变长度行的表(含有VARCHAR、BLOB或TEXT列的表)进行了不少更改,则应实用OPTIMIZE TABLE命令来进行表优化。这个命令能够将表中的空间碎片进行合并,而且能够消除因为删除或者更新形成的表空间浪费,但OPTIMIZE TABLE命令只对MyISAM、BDB和InnoDB表起做用。
当用load命令导入数据的时候,适当的设置能够提升导入的速度。
对于MyISAM存储引擎的表,能够经过如下方式快速地导入大量的数据。
ALTER TALBE tbl_name DISABLE KEYS;
loading the data
ALTER TABLE tbl_name ENABLE KEYS;
复制代码
DISABLE KEYS和ENABLE KEYS用来打开或者关闭MyISAM表非惟一索引的更新。这种方式是对MyISAM表进行数据导入时的优化措施。
有如下几种方式提升InnoDB表的导入效率。
SET UNIQUE_CHECKS=0
,关闭惟一性校验,在导入结束后执行SET UNIQUE_CHECKS=1
,恢复惟一性校验,能够提升导入的效率。SET AUTOCOMMIT=0
,关闭自动提交,导入结束后再执行SET AUTOCOMMIT=1
,打开自动提交,也能够提升导入的效率。当进行数据INSERT的时候,能够考虑采用如下几种优化方式。
INSERT INTO tlb_name VALUES(), (), ..., ()
语句,这种方式将大大缩减客户端与数据库之间的链接、关闭等消耗,使得效率比分开执行的单个INSERT语句快(在大部分状况下,使用多个值表的INSERT语句能比单个INSERT语句快上好几倍)。MySQL中有两种排序方式
第一种经过有序索引顺序扫描直接返回有序数据,这种方式在使用explain分析查询的时候显示为Using index,不须要额外的排序,操做效率较高。
第二种是经过对返回数据进行排序,也就是一般说的FileSort排序,全部不是经过索引直接返回排序结果的排序都叫Filesort排序。Filesort并不表明经过磁盘文件进行排序,而只是说明进行了一个排序操做,至于排序操做是否使用了磁盘文件或临时表等,则取决于MySQL服务器对排序参数的设置和须要排序数据的大小。
Filesort是经过相应的排序算法,将取得的数据在sort_buffer_size系统变量设置的内存排序区中进行排序,若是内存装载不下,它就会将磁盘上的数据进行分块,再对各个数据块进行排序,而后将各个块合并成有序的结果集。sort_buffer_size设置的排序区是每一个线程独占的,因此同一时刻,MySQL中存在多个sort_buffer_size排序区。
若是查询包括GROUP BY但用户想要避免排序结果的消耗,则能够指定ORDER BY NULL禁止排序。
在某些状况下,子查询能够被更有效率的链接(JOIN)替代。
链接(JOIN)之因此更有效率一些,是由于MySQL不须要在内存中建立临时表来完成这个逻辑上须要两个步骤的查询工做。
对于含有OR的查询子句,若是要利用索引,则OR之间的每一个条件都必须用到索引;若是没有索引,则应该考虑增长索引。
第一种优化思路
在索引上完成排序分页的操做,最后根据主键关联回原表查询所须要的其余列内容。
第二种优化思路
把LIMIT查询转换为某个位置的查询。例如,分页的时候,增长last_page_record,用来记录上一页最后一行的id。
注意,这样把LIMIT m, n转换成LIMIT n的查询,只适合在排序字段不会出现重复值的特定环境下,可以减轻分页翻页的压力;若是排序字段出现大量重复值,而仍进行这种优化,那么分页结果可能会丢失部分记录,不适用这种方式优化。
USE INDEX
在查询语句中表名的后面,添加USE INDEX来提供但愿MySQL去参考的索引列表,就可让MySQL再也不考虑其余可用的索引。
mysql> explain select count(*) from rental use index(idx_rental_date);
复制代码
IGNORE INDEX
让MySQL忽略一个或者多个索引,则可使用IGNORE INDEX做为HINT。
mysql> explain select count(*) from rental ignore index(idx_rental_date);
复制代码
FORCE INDEX
强制MySQL使用一个特定的索引,可在查询中使用FORCE INDEX做为HINT。
mysql> explain select * from rental force index(idx_fk_inventory_id) where inventory_id > 1;
复制代码
在MySQL中,可使用函数PROCEDURE ANALYSE()对当前应用的表进行分析,该函数能够对数据表中列的数据类型提出优化建议。
SELECT * FROM tbl_name PROCEDURE ANALYSE();
-- 不要为那些包含的值多于16个或者256个字节的ENUM类型提出建议
SELECT * FROM tbl_name PROCEDURE ANALYSE(16, 256);
复制代码
垂直拆分
若是一张表中某些列经常使用,某些列不经常使用,可使用垂直拆分,另外,垂直拆分可使得数据行变小,一个数据页就能存放更多的数据,在查询时就会减小I/O次数。
缺点是,须要管理冗余列,查询全部数据须要联合(JOIN)操做。
水平拆分
根据一列或多列数据的值把数据行放到两个独立的表中。
反规范的好处是下降链接操做的需求、下降外码和索引的数目,还可能减小表的数目,相应带来的问题是可能出现数据的完整性问题。加快查询速度,但会下降修改速度。
经常使用的范规范技术有增长冗余列、增长派生列、从新组表和分割表。
另外,逆规范化技术须要维护数据的完整性。经常使用的方法是批处理维护、应用逻辑和触发器。
对于数据量较大的表,在其上进行统计查询一般会效率很低,而且要考虑统计查询是否会对在线的应用产生负面影响。一般在这种状况下,使用中间表能够提升统计查询的效率。
MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);DBD存储引擎采用的是页面锁(page-level locking),但也支持表级锁;InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认状况下采用行级锁。
MySQL这3种锁的特性可大体概括以下:
MyISAM存储引擎只支持表锁。
mysql> show status like 'table%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Table_locks_immediate | 3 |
| Table_locks_waited | 0 |
+----------------------------+-------+
复制代码
若是Table_locks_waited的值比较高,则说明存在着较严重的表级锁争用状况。
MySQL表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。
MyISAM在执行查询语句(SELECT)前,会自动给涉及的全部表加读锁,在执行更新操做(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不须要用户干预。
显示加锁与解锁
-- 加读锁
lock table tbl_name read [local];
lock talbes tbl1_name read local, tbl2_name read local;
-- 写锁
lock table tbl_name write;
-- 解锁
unlock tables;
复制代码
MyISAM表也支持查询和插入操做的并发进行。
MyISAM存储引擎有一个系统变量concurrent_insert
,专门用于控制其并发插入的行为,其值分别能够为0、1或2。
MyISAM存储引擎的读锁和写锁都是互斥的,读写操做是串行的。那么,一个进程请求某个MyISAM表的读锁,同时另外一个进程也请求同一个表的写锁,MySQL如何处理呢?答案是写进程先得到锁。不只如此,即便读请求先到锁等待队列,写请求后到,写锁也会插到读锁请求以前!这是由于MySQL认为写请求通常比读请求更重要。这也是MyISAM表不太适合有大量更新操做和查询操做应用的缘由,由于,大量的更新操做会形成查询操做很难得到写锁,从而可能永远阻塞。
能够经过一些设置来调节MyISAM的调度行为。
low-priority-updates
,使MyISAM引擎默认给予读请求以优先的权利。SET LOW_PRIORITY_UPDATES=1
,使该链接发出的更新请求优先级下降。另外,MySQL也提供了一种折中的办法来调节读写冲突,即给系统参数max_write_lock_count
设置一个合适的值,当一个表的读锁达到这个值后,MySQL就暂时将写请求的优先级下降,给读进程必定得到锁的机会。
InnoDB支持事务,采用了行级锁。
事务是由一组SQL语句组成的逻辑处理单元,事务具备4个属性:原子性(Atomicity)、一致性(Consistent)、隔离性(Isolation)、持久性(Durable)。
并发事务带来的问题
事务隔离级别
数据库实现事务隔离的方式,基本上可分为如下两种。
4种隔离性比较
隔离级别\读数据一致性及并发反作用 | 读数据一致性 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
未提交读(Read uncommitted) | 最低级别,只能保证不读取物理上损坏的数据 | 是 | 是 | 是 |
已提交读(Read committed) | 语句级 | 否 | 是 | 是 |
可重复读(Repeatable read) | 事务级 | 否 | 否 | 是 |
可序列化(Serializable) | 最高级别,事务级 | 否 | 否 | 否 |
能够经过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺状况
mysql> show status like 'innodb_row_lock%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0 |
| Innodb_row_lock_time | 0 |
| Innodb_row_lock_time_avg | 0 |
| Innodb_row_lock_time_max | 0 |
| Innodb_row_lock_waits | 0 |
+-------------------------------+-------+
复制代码
若是锁争用状况比较严重,InnoDB_row_lock_waits和InnoDB_row_lock_time_avg的值比较高,能够经过查询 infomation_schema 数据库中相关的表来查看锁状况,或经过设置InnoDB Monitors来进一步观察发生锁冲突的表、数据行等,并分析锁争用的缘由。
InnoDB实现了如下两种类型的行锁。
另外,为了容许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。
上述锁模式的兼容状况具体以下:
当前锁模式\是否兼容\请求锁模式 | X | IX | S | IS |
---|---|---|---|---|
X | 冲突 | 冲突 | 冲突 | 冲突 |
IX | 冲突 | 兼容 | 冲突 | 兼容 |
S | 冲突 | 冲突 | 兼容 | 兼容 |
IS | 冲突 | 兼容 | 兼容 | 兼容 |
意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁;事务能够经过如下语句显示给记录集加共享锁或排他锁。
用 SELECT ... IN SHARE MODE得到共享锁,主要用在须要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操做。可是若是当前事务也须要对该记录进行更新操做,则颇有可能形成死锁,对于锁定行记录后须要进行更新操做的应用,应该使用SELECT ... FOR UPDATE方式得到排他锁。
InnoDB行锁是经过给索引上的索引项加锁来实现的,若是没有索引,InnoDB将经过隐藏的聚簇索引来对记录加锁。InnoDB行锁分为3种情形。
InnoDB这种行锁实现特色意味着:若是不经过索引条件检索数据,那么InnoDB将对表中的全部记录加锁,实际效果跟表锁同样。
注意如下几点:
当咱们使用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但不存在的记录,叫作“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的Next-Key锁。
举例来讲,假如emp表中只有101条记录,其empid的值分别是一、二、...、100、101,下面的SQL:
select * from emp where empid > 100 for update;
复制代码
是一个范围条件的检索,InnoDB不只会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁。
InnoDB使用Next-Key锁的目的,一方面是为了防止幻读,以知足相关隔离级别的要求;另外一方面,是为了知足其恢复和复制的须要。
还要特别说明的是,InnoDB除了经过范围条件加锁时使用Next-Key锁外,若是使用相等条件请求一个不存在的记录加锁,InnoDB也会使用Next-Key锁!
MySQL经过BINLOG记录执行成功的INSERT、UPDATE、DELETE等更新数据的SQL语句,并由此实现MySQL数据库的恢复和主从复制。MySQL 5.6 支持3种日志格式,即基于语句的日志格式SBL、基于行的日志格式RBL和混合格式。还支持4种复制模式。
对基于语句日志格式(SBL)的恢复和复制而言,因为MySQL的BINLOG是按照事务提交的前后顺序记录的,所以要正确恢复或复制数据,就必须知足:在一个事务未提交前,其余并发事务不能插入知足其锁定条件的任何记录,也就是不容许出现幻读。这已经超过了ISO/ANSI SQL92“可重复读”隔离级别的要求,其实是要求事务要串行化。这也是许多状况下,InnoDB要用到Next-Key锁的缘由,好比在用范围条件更新记录时,不管实在Read Commited或是Repeatable Read隔离级别下,InnoDB都要使用Next-Key锁,但这并非隔离级别要求的。
ISNERT ... SELECT ... 和 CREATE TALBE ... SELECT ..语句,可能会阻止对源表的并发更新。若是查询比较复杂,会形成严重的性能问题,读者在应用中应尽可能避免使用。实际上,MySQL将这种SQL叫作不肯定(non-deterministic)的SQL,属于“Unsafe SQL”,不推荐使用。
在InnoDB下,使用表锁要注意如下两点。
MyISAM表锁是deadlock free的,这是由于MyISAM老是一次得到所需的所有锁,要么所有知足,要么等待,所以不会出现死锁。但在InnoDB中,除单个SQL组成的事务外,锁是逐步得到的,这就决定了在InnoDB中发生死锁是有可能的。
发生死锁后,InnoDB通常都能自动检测到,并使一个事务释放锁并回退,另外一个事务得到锁,继续完成事务。但在涉及外部锁或涉及表锁的状况下,InnoDB并不能彻底自动检测到死锁,这须要经过设置锁等待超时参数innodb_lock_wait_timeout
来解决。须要说明的是,这个参数并非只用来解决死锁问题,在并发访问比较高的状况下,若是大量事务因没法当即得到所需的锁而挂起,会占用大量计算机资源,形成严重性能问题,设置拖垮数据库。咱们经过设置合适的锁等待超时阈值,能够避免这种状况发生。
避免死锁的经常使用方法: