1. 程式人生 > >SQL基礎教程閱讀筆記

SQL基礎教程閱讀筆記

資料庫分類

層次型資料庫 Hierarchical Database HDB
將資料通過層次結構(樹形結構)儲存,層次型資料庫現在很少使用。

關係型資料庫 Relational Database RDB
和Excel一樣,使用行列二維表的結構管理資料,使用專門的SQL(Structured Query Language資料化查詢語言)語言對資料進行操作。

RDB使用的DBMS(Database Managment System)稱為RDBMS(Relational Database Management Language),常用的如下:
-Oracle Database
-SQL Server
-DB2
-PostgreSQL
-MySQL

面向物件資料庫(Object Oriented Database OODB)
將資料以及資料的操作抽象為物件進行管理

XML資料庫(XML Database XMLDB)
使用xml形式儲存,可以對大量資料進行高速處理

鍵值儲存系統(Key-Value Store KVS)
使用鍵值對儲存資料,可以理解為關聯陣列或者雜湊hash

SQL語句和種類

標準化SQL和特定SQL
ISO制定了SQL標準,不同的SQL廠家(Oracle,DB2,MySQL)會新增特定的SQL。

DDL Data Definition Language 資料定義語言 用於建立或者刪除儲存資料用的資料庫或者資料庫中的表
CREATE 建立資料庫和表
DROP 刪除資料庫和表
ALTER 修改資料庫和表

建立資料庫

CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
[create_specification] ...

create_specification:
[DEFAULT] CHARACTER SET [=] charset_name
| [DEFAULT] COLLATE [=] collation_name

建立表

參考 https://dev.mysql.com/doc/refman/5.7/en/create-table.html

修改資料庫

ALTER {DATABASE | SCHEMA} [db_name]
alter_specification ...
ALTER {DATABASE | SCHEMA} db_name
UPGRADE DATA DIRECTORY NAME

alter_specification:
[DEFAULT] CHARACTER SET [=] charset_name
| [DEFAULT] COLLATE [=] collation_name

可以修改資料庫編碼,排序以及資料庫名稱。

ALTER DATABASE #mysql50#.miya1102 UPGRADE DATA DIRECTORY NAME;修改庫名

修改資料庫表

參考 ttps://dev.mysql.com/doc/refman/5.7/en/alter-table.html

刪除資料庫

DROP {DATABASE | SCHEMA} [IF EXISTS] db_name

資料庫刪除後會同時刪除所有的表資訊(資料恢復可以設定binlog防止誤刪除)。

刪除資料庫表

DROP [TEMPORARY] TABLE [IF EXISTS]
tbl_name [, tbl_name] ...
[RESTRICT | CASCADE]

清空表

TRUNCATE [TABLE] tbl_name

DML Data Manipulation Language 資料操作語言 查詢或者表更表中的記錄
SELECT 查詢表中資料
INSERT 向表中插入資料
UPDATE 更新表中資料
DELETE 刪除表中資料

插入資料

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
{VALUES | VALUE} (value_list) [, (value_list)] ...
[ON DUPLICATE KEY UPDATE assignment_list]

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
SET assignment_list
[ON DUPLICATE KEY UPDATE assignment_list]

INSERT ... SELECT(從現有表查詢資料並插入目標表)

INSERT INTO tbl_temp2 (fld_id)
SELECT tbl_temp1.fld_order_id
FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;

INSERT ... ON DUPLICATE KEY UPDATE (KEY值重複時進行更新操作,否則進行插入操作)

INSERT INTO t1 (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;

如果存在c=3的資料,執行完成後c變成4.

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
SELECT ...
[ON DUPLICATE KEY UPDATE assignment_list]

value:
{expr | DEFAULT}

value_list:
value [, value] ...

assignment:
col_name = value

assignment_list:
assignment [, assignment] ...

可以使用REPLACE來替換舊有的值,相當於INSERT IGNORE。

查詢資料

mysql可以從一個或者多個表查詢資料,並且支援子查詢。

UNION(聯合查詢)

SELECT ...
UNION [ALL | DISTINCT] SELECT ...
[UNION [ALL | DISTINCT] SELECT ...]

第一張表的列名作為結果的列名,使用ALL不會刪除重複行,DISTINCT為預設值,刪除重複結果。

如果需要使用ORDER BY,就要將查詢子句使用括號括起來。如果需要對最終結果使用ORDER BY,也需要將每個子句括起來。

subquery(子查詢)

SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

SELECT * FROM t1稱為外查詢,SELECT column1 FROM t2稱為子查詢。

子查詢可以用於查詢比較結果,比如
SELECT * FROM t1
WHERE column1 = (SELECT MAX(column1) FROM t1);

子查詢可以使用ANY, IN或者SOME(SOME和ANY是一樣的)

格式為 select .. comparison_operator ANY | IN | SOME (subquery)

comparison_operator:= > < >= <= <> !=

ANY 滿足任一子查詢條件即可
ALL 滿足子查詢的所有查詢
SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN (SELECT s1 FROM t2);

ROW子查詢(可以匹配多個子查詢的結果欄位,操作符 = > < >= <= <> != <=>(安全比較符號,可以比較NULL))

SELECT * FROM t1
WHERE (col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);

SELECT * FROM t1
WHERE ROW(col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);

子查詢使用EXISTS和NOT EXISTS(將子查詢作為判斷條件,有結果則執行父查詢)

SELECT DISTINCT store_type FROM stores s1
WHERE NOT EXISTS (
SELECT * FROM cities WHERE NOT EXISTS (
SELECT * FROM cities_stores
WHERE cities_stores.city = cities.city
AND cities_stores.store_type = stores.store_type));

子查詢使用AVG(),SUM(),MAX(),MIN(),COUNT()這樣的聚合函式,只會返回一個查詢結果稱為標量子查詢(Scalar subquery)。標量子查詢可以查詢出符合條件的值,但是需要注意的是標量子查詢只能返回一個查詢結果,返回多個結果會發生錯誤。

關聯子查詢

當標量子查詢需要進行分組時(返回多個結果),可以使用關聯子查詢(即將最外層查詢的結果與子查詢結果使用where進行比較(=等等)。

SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr ...]
[FROM table_references
[PARTITION partition_list]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]]

更新表資料

UPDATE [LOW_PRIORITY] [IGNORE] table_reference
SET assignment_list
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]

value:
{expr | DEFAULT}

assignment:
col_name = value

assignment_list:
assignment [, assignment] ...

DCL Data Controller Language 資料控制語言 用來確認或者取消對資料庫中資料的表更,以及對資料庫操作許可權進行設定
COMMIT 確認對資料庫資料進行表更
ROLLBACK 取消對資料庫資料進行變更
GRANT 賦予使用者操作許可權
REVOKE 取消使用者操作許可權

建表語句

CREATE TABLE 表名
( 列名1,資料型別,列所需約束,
列名2,資料型別,列所需約束,
...,
表約束1,表約束2...);

CREATE TABLE Shohin
(shohin_id CAHR(4) NOT NULL,
shohin_mei VARCHAR(100) NOT NULL,
shohin_bunrui INTEGER ,
hanbai_tanka INTEGER ,
torokubi DATE ,
PRIMARY KEY (shohin_id));

MySQL資料型別

Numeric 數字型別

INTEGER | INT
預設建立的都是有符號整型資料(signed)

Type Storage (Bytes) Minimum Value Signed Minimum Value Unsigned Maximum Value Signed Maximum Value Unsigned
TINYINT 1 -128(2^7) 0 127(2^7-1) 255(2^8)
SMALLINT 2 -32768 0 32767 65535
MEDIUMINT 3 -8388608 0 8388607 16777215
INT 4 -2147483648 0 2147483647 4294967295
BIGINT 8 -2^63 0 2^63-1 2^64-1

MySQL中TINYINT(1)和TINYINT(2)的區別(只有使用了zerofill並且設定為unsigned才有區別)

CREATE TABLE test (
id int(11) NOT NULL AUTO_INCREMENT,
str varchar(255) NOT NULL,
state tinyint(1) unsigned zerofill DEFAULT NULL,
state2 tinyint(2) unsigned zerofill DEFAULT NULL,
state3 tinyint(3) unsigned zerofill DEFAULT NULL,
state4 tinyint(4) unsigned zerofill DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8

insert into test (str,state,state2,state3,state4) values('csdn',4,4,4,4);
select * from test;
結果:
id   str      state   state2   state3   state4 
1    csdn  4         04         004        0004

NUMERIC和DECIMAL

MYSQL中DECIMAL就是NUMERIC的實現,所以他們的作用是一樣的。
用來表示精確的數字比如貨幣是一般使用DECIMAL,根據國際會計規定,需要保留四位小數。
使用方法
column_name DECIMAL(P,D);

在上面的語法中:

  • P是表示有效數字數的精度。 P範圍為1〜65。
  • D是表示小數點後的位數。 D的範圍是0~30。MySQL要求D小於或等於(<=)P。

浮點型資料

MYSQL使用FLOAT和DOUBLE兩種浮點型資料。

可以使用FLOAT(M,D)或者FLOAT以及DOUBLE(M,D) M表示數字精度,D表示小數點後位數,DOUBLE PRECISION(M,D)。
float的範圍為-2^128 ~ +2^128,也即-3.40E+38(-3.40*10^38) ~ +3.40E+38;double的範圍為-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308。

位元型別資料

使用BIT儲存位元型別資料,BIT(M) enables storage of M-bit values. M can range from 1 to 64.

字串型別資料

CHAR和VARCHAR用來儲存字串資料,兩者的區別就是最大資料範圍。

CHAR(M)和VARCHAR(M)M表示可以儲存的最大長度,CHAR的資料長度範圍為0到255,VARCHAR的資料長度範圍為0到65535。

BINARY和VARBINARY兩種型別和CHAR和VARCHAR兩種型別高度一致,唯一的區別就是其儲存的是二進位制的字串資料。

大資料量型別

BLOB和TEXT可以儲存大資料量的字串型別。BLOB可以儲存照片(其儲存的是二進位制資料),而TEXT只能儲存文字資訊。

一般情況下避免使用BLOB和TEXT,因為對其進行的刪除操作會導致資料庫留下空洞,依然會佔用資料庫記憶體,解決的方法是使用OPTIMEIZE TABLE回收資源。

查詢BLOB和TEXT資料的時候,儘量使用合成索引(對於BLOB或者TEXT資料進行雜湊MD5()函式),可以提升查詢速度。

TEXT值被建立索引後,mySQL在其末尾填充空格,則如果不同的TEXT值具有相同的字首,會發生鍵值重複錯誤,BLOB不存在這樣的問題。

BLOB和TEXT列不能具有DEFAULT值。

BLOB和TEXT排序時使用的是前max_sort_length個字元,如果需要可以修改:SET max_sort_length = 2000;

BLOB和TEXT的最大大小可以進行設定。

列舉型別

ENUM和SET可以放在一起看,ENUM的使用方法是定義列為ENUM('a','b','c'),那麼列的值只能為其中之一。SET定義列為SET('one', 'two'),那麼其值可以是'','one','two','one,two'。

stackoverflow上面有個高分答案是ENUM可以理解為單選欄位(radio fields),SET可以理解為多選欄位(checkbox fields)。

ENUM的元素數量理論限制是65535,實際是不超過3000.

日期和時間型別

DATE, DATETIME, TIMESTAMP

DATE用來表示純日期格式,形如'YYYY-MM-DD' ,區間為 '1000-01-01' 到 '9999-12-31'.

DATETIME用來表示日期和時間,形如'YYYY-MM-DD HH:MM:SS',區間為'1000-01-01 00:00:00' 到 '9999-12-31 23:59:59'.

TIMESTAMP用來表示日期和時間,形如'YYYY-MM-DD HH:MM:SS',區間為 '1970-01-01 00:00:01' UTC到 '2038-01-19 03:14:07' UTC.

DATETIME和TIMESTAMP可以設定預設值及自動更新為當前時間,具體可以參考https://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization.html。

CREATE TABLE t1 (
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

TIME

TIME的格式是'HH:MM:SS',區間為'-838:59:59' to '838:59:59'(大時間使用'HHH:MM:SS',可能表示兩個時間之間的間隔)。

YEAR

YEAR的格式是YYYY,區間為1901到2155,空值為0000.

空間資料型別

涉及較少,有需要再做相應的瞭解(https://dev.mysql.com/doc/refman/5.7/en/spatial-types.html)。

聚合查詢

聚合查詢用於處理一組資料

Name Description
AVG() 返回平均值
COUNT() 計算表中記錄數
SUM() 計算總值
MAX() 返回最大值
MIN() 返回最小值

聚合函式會忽略NULL值。

聚合函式一般搭配 GROUP BY使用,如果不使用GROUP BY即相當於將每一行資料單獨分組。

只有Select和Having子句可以使用聚合函式

select t1 from s1 where sum(t1) > 2; //函式sum()使用錯誤,只有select和having子句可以使用

Having

制定特定條件用來分組

select 列名1,列名2...
from 表名
group by 列名1,列名2,列名3
having 分組條件

事務

事務是需要在同一處理但願中執行的一系列更新操作的集合

建立事務

MYSQL使用自動提交,DML語句會自動被執行,而使用START TRANSACTION會關閉自動提交,直到呼叫COMMIT才會提交DML,ROLLBACK會回退事務所有DML。
START TRANSACTION(BEGIN);

DML1;
DML2;
...
COMMIT(ROLLBACK);

ROLLBACK對於DDL(資料庫定義語句)不起作用。

事務隔離級別 Transaction Isolation Levels

事務隔離級別分類

REPEATABLE READ 可重複讀取
InnoDB的預設事務級別。同一事物內第一次讀取MYSQL會建立快照,以後的讀取結果都是這個快照。(可能會有幻讀情況,即併發事務修改了資料,事務完成後再次查詢出現不一樣的結果)

READ COMMITTED 讀已提交
同一事務內,每次讀取獲取的都是獨立的快照結果,可能會有不可重複讀的問題(併發事務可能導致無法預料的錯誤)。

READ UNCOMMITTED 讀未提交
事務所作的修改在未提交前,其他併發事務是可以讀到修改後的值,可能會出現髒讀問題。

SERIALIZABLE 可序列化
解決了幻讀的問題,但是效能比較低。

設定事務隔離級別

SET [GLOBAL | SESSION] TRANSACTION
transaction_characteristic [, transaction_characteristic] ...

transaction_characteristic: {
ISOLATION LEVEL level
| access_mode
}

level: {
REPEATABLE READ
| READ COMMITTED
| READ UNCOMMITTED
| SERIALIZABLE
}

access_mode: {
READ WRITE
| READ ONLY
}

複雜查詢

檢視可以理解為儲存SQL語句的容器,其本身沒有儲存資料。(從SQL的角度來看,表和檢視沒有區別)

檢視語法

建立檢視

CREATE | REPLACE //CREATE建立檢視,REPLACE替換或者建立檢視
[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] //MYSQL優化檢視的演算法
[DEFINER = { user | CURRENT_USER }] //檢視的建立者
[SQL SECURITY { DEFINER | INVOKER }] //指定檢視查詢資料時的安全驗證方式
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION] //可更新檢視的限制條件

[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
對於MERGE,引用檢視和檢視定義的語句的文字被合併,以便檢視定義的部分替換語句的相應部分。

對於TEMPTABLE,來自檢視的結果被檢索到一個臨時表中,然後該臨時表用於執行語句。

對於UNDEFINED,MySQL選擇使用哪個演算法。如果可能的話,它更喜歡MERGE而不是TEMPTABLE,因為MERGE通常效率更高,並且因為如果使用臨時表,檢視是不可更新的。

建立檢視
CREATE VIEW shohinSum(shohin_bunrui,cnt_shohin)
AS
SELECT shohin_bunrui,COUNT(*)
FROM shohin
GROUP BY shohin_bunrui;

SELECT shohin_bunrui,cnt_shohin
FROM shohinSUM;

檢視的限制

檢視中不能使用ORDER BY。

以下檢視不能更新:

  • 檢視中使用了聚合函式(SUM(), MIN(), MAX(), COUNT()等等)
  • 檢視中使用了DISTINCT
  • 檢視中使用了GROUP BY
  • 檢視中使用了HAVING
  • 檢視中使用了 UNION 或者 UNION ALL
  • 檢視演算法設定ALGORITHM = TEMPTABLE

MYSQL的檢視是否可以更新或者插入可以通過查詢對應的標識位查詢(https://dev.mysql.com/doc/refman/5.7/en/views-table.html)。

函式,謂詞,CASE表示式

函式分類

表聯結運算

UNION(聯合查詢)

SELECT ...
UNION [ALL | DISTINCT] SELECT ... //ALL選項會包含重複的結果,DISTINCT是預設值,會去除重複值
[UNION [ALL | DISTINCT] SELECT ...]

第一張表的列名作為結果的列名,使用ALL不會刪除重複行,DISTINCT為預設值,刪除重複結果。

如果需要對單個使用ORDER BY,就要將查詢子句使用括號括起來。如果需要對最終結果使用ORDER BY,也需要將每個子句括起來。(網上有些部落格說UNION查詢中ORDER BY只能對最終結果使用,這種說法是錯誤的,可以參考官方文件 https://dev.mysql.com/doc/refman/5.7/en/union.html

(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;

INTERSECT 交集查詢

MYSQL不支援INTERCSECT,可以使用INNER JOIN實現查詢表記錄的交集。

EXCEPT 表記錄的減法

MYSQL不支援EXCEPT,可以使用NOT IN實現查詢兩表差異化的記錄。

查詢結果為表記錄共有的部分。

聯結查詢(以列為單位對錶進行聯結)

使用聯結可以實現從多張表查詢記錄,使用列記錄進行關聯。

內聯結 INNER JOIN
內聯結可以理解為:以表A中列作為橋樑,將表B中滿足條件的列彙集到同一結果中。

基本的內聯結語句:
SELECT t1.name, t2.salary
FROM employee AS t1 INNER JOIN info AS t2 ON t1.name = t2.name;

內聯結和where聯合使用語句(只查詢符合要求的資料):
SELECT t1.name, t2.salary
FROM employee AS t1 INNER JOIN info AS t2 ON t1.name = t2.name
WHERE t1.id < 100;

外聯結 OUTER JOIN

外聯結即查詢出主表所有符合條件的記錄,不管副表中是否存在記錄,副表不存在的記錄列使用NULL表示。

LEFT (OUTER) JOIN和RIGHT (OUTER) JOIN中的LEFT和RIGHT表示左邊或者右邊的表是主表。

視窗函式

MYSQL從8.0版本開始支援視窗函式,視窗函式可以和GROUP BY分組函式進行比較以方便理解。

比如有一個分組函式:

SELECT
fiscal_year,
SUM(sale)
FROM
sales
GROUP BY
fiscal_year;

類似的視窗函式:

SELECT
fiscal_year,
sales_employee,
sale,
SUM(sale) OVER (PARTITION BY fiscal_year) total_sales
FROM
sales;

資料劃分(PARTITION)

可以將一張表劃分為不同的部分,比如按照DATE, TIME, 或者 DATETIME對錶資料進行劃分,一般用在資料量比較大的表中。

MySQL分割槽不能與MERGE、CSV或FEDERATED儲存引擎一起使用。

PARTITION TYPE

  • RANGE partitioning 基於給定的rank範圍對資料進行分組

RANGE定義分組時每組值不能相接只能相鄰,並且要使用LESS THAN(),最後的分割槽設定為MAXVALUE。
使用例項

使用整數值的列對錶記錄進行劃分

CREATE TABLE members (
firstname VARCHAR(25) NOT NULL,
lastname VARCHAR(25) NOT NULL,
username VARCHAR(16) NOT NULL,
email VARCHAR(35),
joined DATE NOT NULL
)
PARTITION BY RANGE( YEAR(joined) ) (
PARTITION p0 VALUES LESS THAN (1960),
PARTITION p1 VALUES LESS THAN (1970),
PARTITION p2 VALUES LESS THAN (1980),
PARTITION p3 VALUES LESS THAN (1990),
PARTITION p4 VALUES LESS THAN MAXVALUE
);

使用 TIMESTAMP 型別的列對錶記錄進行劃分

CREATE TABLE quarterly_report_status (
report_id INT NOT NULL,
report_status VARCHAR(20) NOT NULL,
report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
PARTITION p9 VALUES LESS THAN (MAXVALUE)
);

  • LIST partitioning

LIST分割槽和TRANGE分割槽很相似,它們最大的區別是LIST分割槽是用一組值對資料進行劃分,這樣的劃分方式更為靈活。

CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY LIST(store_id) (
PARTITION pNorth VALUES IN (3,5,6,9,17),
PARTITION pEast VALUES IN (1,2,10,11,19,20),
PARTITION pWest VALUES IN (4,12,13,14,18),
PARTITION pCentral VALUES IN (7,8,15,16)
);

可以使用ALTER TABLE employees TRUNCATE PARTIT.pWest刪除pWest分組中的所有資料。
LIST分割槽不存在RANKE分割槽類似的MAXVALUE,因此分組時需要將所有可能值豆包括進去,不然插入未包含資料時會報錯。

  • RANGE COLUMNS partitioning

RANGE partitioning的變體,支援使用多列進行分割槽,但是不能使用表示式。(可以使用的列包括 integer,string, DATE和DATETIME列)

CREATE TABLE table_name
PARTITIONED BY RANGE COLUMNS(column_list) (
PARTITION partition_name VALUES LESS THAN (value_list)[,
PARTITION partition_name VALUES LESS THAN (value_list)][,
...]
)

CREATE TABLE rcx (
a INT,
b INT,
c CHAR(3),
d INT
)
PARTITION BY RANGE COLUMNS(a,d,c) (
PARTITION p0 VALUES LESS THAN (5,10,'ggg'),
PARTITION p1 VALUES LESS THAN (10,20,'mmm'),
PARTITION p2 VALUES LESS THAN (15,30,'sss'),
PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)
);

比較RANGE區間的值大小可以使用sql語句
SELECT (0,25,50) < (20,20,100), (20,20,100) < (10,30,50);

RANGE COLUMNS partitioning可以對字串列進行分組,並且MAXVALUE值可以生效
CREATE TABLE employees_by_lname (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE COLUMNS (lname) (
PARTITION p0 VALUES LESS THAN ('g'),
PARTITION p1 VALUES LESS THAN ('m'),
PARTITION p2 VALUES LESS THAN ('t'),
PARTITION p3 VALUES LESS THAN (MAXVALUE)
);

  • LIST COLUMNS partitioning

LIST partitioning的變體,支援使用多個列作為分割槽健,並且在integer型別之外,還支援包括string,DATE,DATETIME型別的列。

  • KEY partitioning
    KEY partitioning和HASH partitioning很像,不同的是由MYSQL決定使用什麼演算法來獲得分割槽值:
    CREATE TABLE k1 (
    id INT NOT NULL PRIMARY KEY,
    name VARCHAR(20)
    )
    PARTITION BY KEY()
    PARTITIONS 2;

MYSQL優先使用主鍵或者聯合主鍵作為分割槽的key,如果沒有主鍵的話就使用UNIQUE KEY,但是UNIQUE KEY你許定義為NOT NULL。

  • HASH partitioning

HASH分割槽主要用來保證資料在指定的分割槽內均勻分佈。

使用HASH partitioning的話需要在建立表的時候進行定義,如:

CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY HASH( YEAR(hired) )
PARTITIONS 4;

MYSQL使用取模的方法決定資料存放在哪個分割槽,比如以上定義的分割槽中,如果hired為'2005-01-01',則分割槽為MOD(YEAR('2005-01-01'),4)=MOD(2005,40)=1.

LINEAR HASH Partitioning

MYSQL還支援線性雜湊分割槽,其與HASH partitioning語句的唯一區別是添加了LINEAR關鍵字:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY LINEAR HASH( YEAR(hired) )
PARTITIONS 4;

線性分割槽使用的時候,新增,刪除,合併和分割的時候速度更快,處理TB級別的資料時更加有優勢,但是不能保證資料平均分佈在各個分割槽(由分割槽公式決定,可參考:https://dev.mysql.com/doc/refman/5.7/en/partitioning-linear-hash.html

  • Subpartitioning

子分割槽或者稱為混合分割槽(composite),是將分割槽表後的每一個分割槽繼續劃分。

對於使用RANGE或者LIST進行分割槽的表,可以再用HASH或者KEY進行分割槽。
以下表使用了RANGE( YEAR(purchased) )進行分割槽,然後定義了子分割槽HASH( TO_DAYS(purchased) ),分割槽邏輯為先根據RANGE( YEAR(purchased) )分為了三個分割槽,每個分割槽中的資料再根據HASH( TO_DAYS(purchased) )分為兩個子分割槽(即3 * 2=6個分割槽)。
CREATE TABLE ts (id INT, purchased DATE)
PARTITION BY RANGE( YEAR(purchased) )
SUBPARTITION BY HASH( TO_DAYS(purchased) )
SUBPARTITIONS 2 (
PARTITION p0 VALUES LESS THAN (1990),
PARTITION p1 VALUES LESS THAN (2000),
PARTITION p2 VALUES LESS THAN MAXVALUE
);

CREATE TABLE ts (id INT, purchased DATE)
PARTITION BY RANGE(YEAR(purchased))
SUBPARTITION BY HASH(TO_DAYS(purchased))
(
PARTITION p0 VALUES LESS THAN (1990)
(SUBPARTITION s0,
SUBPARTITION s1 ),
PARTITION p1 VALUES LESS THAN (2000)
(SUBPARTITION s2,
SUBPARTITION s3 ),
PARTITION p2 VALUES LESS THAN MAXVALUE
(SUBPARTITION s4,
SUBPARTITION s5)
);

管理 PARTITION

RANGE和LIST分割槽

使用DROP可以直接刪除舊的PARTITION(RANGE和LIST):

CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY LIST(store_id) (
PARTITION pNorth VALUES IN (3,5,6,9,17),
PARTITION pEast VALUES IN (1,2,10,11,19,20),
PARTITION pWest VALUES IN (4,12,13,14,18),
PARTITION pCentral VALUES IN (7,8,15,16)
);

ALTER TABLE employees DROP PARTITION pNorth;

當刪除分割槽的時候,分割槽中的資料也被刪除。

刪除LIST 分割槽後,將無法插入LIST分割槽中包含的列的值。

使用ALTER TABLE ... ADD PARTITION可以新增新的分割槽定義到RANGE和LIST分割槽的表中:
CREATE TABLE members (
id INT,
fname VARCHAR(25),
lname VARCHAR(25),
dob DATE
)
PARTITION BY RANGE( YEAR(dob) ) (
PARTITION p0 VALUES LESS THAN (1980),
PARTITION p1 VALUES LESS THAN (1990),
PARTITION p2 VALUES LESS THAN (2000)
);

ALTER TABLE members ADD PARTITION (PARTITION p3 VALUES LESS THAN (2010));

新增到RANGE分割槽的表中時,只能新增分割槽值大於原有值的分割槽。

比如以上表使用以下語句會報錯:
ALTER TABLE members ADD PARTITION (PARTITION n VALUES LESS THAN (1970));

想要實現以上需求的話可以使用以下語句重構第一個分割槽:
ALTER TABLE members
REORGANIZE PARTITION p0 INTO (
PARTITION n0 VALUES LESS THAN (1970),
PARTITION n1 VALUES LESS THAN (1980)
);

新增新的LIST分割槽時,使用任何已經被使用的分割槽值都會報錯。

HASH和KEY分割槽

使用ALTER TABLE ... DROP PARTITION...可以刪除HASH和KEY分割槽,區別於RANGE和LIST分割槽的是可以使用ALTER TABLE ... COALESCE PARTITION將分割槽進行合併:

CREATE TABLE clients (
id INT,
fname VARCHAR(30),
lname VARCHAR(30),
signed DATE
)
PARTITION BY HASH( MONTH(signed) )
PARTITIONS 12;

ALTER TABLE clients COALESCE PARTITION 4; //將12個分割槽合併為4個

[1]: MySQL資料型別之TEXT與BLOB
[2]: mysql中find_in_set()函式的使用
[3]: MYSQL常用函式查詢