它和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
來解決。須要說明的是,這個參數並非只用來解決死鎖問題,在併發訪問比較高的狀況下,若是大量事務因沒法當即得到所需的鎖而掛起,會佔用大量計算機資源,形成嚴重性能問題,設置拖垮數據庫。咱們經過設置合適的鎖等待超時閾值,能夠避免這種狀況發生。
避免死鎖的經常使用方法: