select distinct '字段'
from '表'
join '表' on '條件'
where '條件'
group by '字段'
having '條件'
order by '字段'
limit '條件'
複製代碼
from '表'
on '條件'
'join類型' join '表'
where '條件'
group by '字段'
having '條件'
select distinct '字段'
order by '字段'
limit '條件'
複製代碼
索引(
Index
)是幫助MySQL高效獲取數據的數據結構。在數據以外,數據庫系統還維護着知足特定查找算法的數據結構,這些數據結構以某種方式指向數據,這樣就能夠在這些數據結構上實現高效的查找算法.這種數據結構,就是 索引.
通常來講索引自己也很大,不可能所有存儲在內存中,所以每每以索引文件的形式存放在磁盤中.咱們日常所說的索引,若是沒有特別說明都是指BTree
索引(平衡多路搜索樹).其中彙集索引,次要索引,覆蓋索引複合索引,前綴索引,惟一索引默認都是使用的BTree
索引,統稱索引. 除了BTree
索引以後,還有哈希索引mysql
Index
)是幫助MySQL高效獲取數據的數據結構。不一樣的引擎使用的數據結構也不盡相同.BTree
, InnoDB採起的是B+TREE
B+TREE
.B+樹索引是B+樹在數據庫中的一種實現,是最多見也是數據庫中使用最爲頻繁的一種索引。B+樹中的B表明平衡(balance),而不是二叉(binary),由於B+樹是從最先的平衡二叉樹演化而來的。在講B+樹以前必須先了解二叉查找樹、平衡二叉樹(AVLTree
)和平衡多路查找樹(B-Tree
),B+樹即由這些樹逐步優化而來。二叉樹具備如下性質:左子樹的鍵值小於根的鍵值,右子樹的鍵值大於根的鍵值。 以下圖所示就是一棵二叉查找樹算法
二叉查找樹能夠任意地構造,一樣是2,3,5,6,7,8這六個數字,也能夠按照下圖的方式來構造:sql
平衡二叉樹(AVL樹)在符合二叉查找樹的條件下,還知足任何節點的兩個子樹的高度最大差爲1。下面的兩張 圖片,左邊是AVL樹,它的任何節點的兩個子樹的高度差<=1;右邊的不是AVL樹,其根節點的左子樹高度爲3,而 右子樹高度爲1;數據庫
這四種失去平衡的姿態都有各自的定義:緩存
LL:LeftLeft,也稱「左左」。插入或刪除一個節點後,根節點的左孩子(Left Child)的左孩子(Left Child)還有非 空節點,致使根節點的左子樹高度比右子樹高度高2,AVL樹失去平衡。
RR:RightRight,也稱「右右」。插入或刪除一個節點後,根節點的右孩子(Right Child)的右孩子(Right Child) 還有非空節點,致使根節點的右子樹高度比左子樹高度高2,AVL樹失去平衡。
LR:LeftRight,也稱「左右」。插入或刪除一個節點後,根節點的左孩子(Left Child)的右孩子(Right Child)還有 非空節點,致使根節點的左子樹高度比右子樹高度高2,AVL樹失去平衡。
RL:RightLeft,也稱「右左」。插入或刪除一個節點後,根節點的右孩子(Right Child)的左孩子(Left Child)還有 非空節點,致使根節點的右子樹高度比左子樹高度高2,AVL樹失去平衡。服務器
AVL樹失去平衡以後,能夠經過旋轉使其恢復平衡。下面分別介紹四種失去平衡的狀況下對應的旋轉方法。 LL的旋轉。LL失去平衡的狀況下,能夠經過一次旋轉讓AVL樹恢復平衡。步驟以下:數據結構
LL旋轉示意圖以下:併發
RR的旋轉:RR失去平衡的狀況下,旋轉方法與LL旋轉對稱,步驟以下:函數
RR旋轉示意圖以下:高併發
LR的旋轉:LR失去平衡的狀況下,須要進行兩次旋轉,步驟以下:
LR的旋轉示意圖以下:
RL的旋轉:RL失去平衡的狀況下也須要進行兩次旋轉,旋轉方法與LR旋轉對稱,步驟以下:
RL的旋轉示意圖以下:
B-Tree是爲磁盤等外存儲設備設計的一種平衡查找樹。所以在講B-Tree以前先了解下磁盤的相關知識。
系統從磁盤讀取數據到內存時是以磁盤塊(block)爲基本單位的,位於同一個磁盤塊中的數據會被一次性讀取出 來,而不是須要什麼取什麼。
InnoDB存儲引擎中有頁(Page)的概念,頁是其磁盤管理的最小單位。InnoDB存儲引擎中默認每一個頁的大小爲 16KB,可經過參數innodb_page_size將頁的大小設置爲4K、8K、16K.
而系統一個磁盤塊的存儲空間每每沒有這麼大,所以InnoDB每次申請磁盤空間時都會是若干地址連續磁盤塊來達到 頁的大小16KB。InnoDB在把磁盤數據讀入到磁盤時會以頁爲基本單位,在查詢數據時若是一個頁中的每條數據都 能有助於定位數據記錄的位置,這將會減小磁盤I/O次數,提升查詢效率。
一棵m階的B-Tree有以下特性:
B-Tree中的每一個節點根據實際狀況能夠包含大量的關鍵字信息和分支,以下圖所示爲一個3階的B-Tree:
每一個節點佔用一個盤塊的磁盤空間,一個節點上有兩個升序排序的關鍵字和三個指向子樹根節點的指針,指針存儲 的是子節點所在磁盤塊的地址。兩個關鍵詞劃分紅的三個範圍域對應三個指針指向的子樹的數據的範圍域。以根節 點爲例,關鍵字爲17和35,P1指針指向的子樹的數據範圍爲小於17,P2指針指向的子樹的數據範圍爲17~35,P3 指針指向的子樹的數據範圍爲大於35。
模擬查找關鍵字29的過程:
分析上面過程,發現須要3次磁盤I/O操做,和3次內存查找操做。因爲內存中的關鍵字是一個有序表結構,能夠利用 二分法查找提升效率。而3次磁盤I/O操做是影響整個B-Tree查找效率的決定因素。B-Tree相對於AVLTree縮減了節 點個數,使每次磁盤I/O取到內存的數據都發揮了做用,從而提升了查詢效率。
B+Tree是在B-Tree基礎上的一種優化,使其更適合實現外存儲索引結構,InnoDB存儲引擎就是用B+Tree實現其索 引結構。
從上一節中的B-Tree結構圖中能夠看到每一個節點中不只包含數據的key值,還有data值。而每個頁的存儲空間是 有限的,若是data數據較大時將會致使每一個節點(即一個頁)能存儲的key的數量很小,當存儲的數據量很大時同 樣會致使B-Tree的深度較大,增大查詢時的磁盤I/O次數,進而影響查詢效率。在B+Tree中,全部數據記錄節點都 是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點上只存儲key值信息,這樣能夠大大加大每一個節點 存儲的key值數量,下降B+Tree的高度。
B+Tree相對於B-Tree有幾點不一樣:
將上一節中的B-Tree優化,因爲B+Tree的非葉子節點只存儲鍵值信息,假設每一個磁盤塊能存儲4個鍵值及指針信 息,則變成B+Tree後其結構以下圖所示:
一般在B+Tree上有兩個頭指針,一個指向根節點,另外一個指向關鍵字最小的葉子節點,並且全部葉子節點(即數據 節點)之間是一種鏈式環結構。所以能夠對B+Tree進行兩種查找運算:一種是對於主鍵的範圍查找和分頁查找,另 一種是從根節點開始,進行隨機查找。
可能上面例子中只有22條數據記錄,看不出B+Tree的優勢,下面作一個推算:
InnoDB存儲引擎中頁的大小爲16KB,通常表的主鍵類型爲INT(佔用4個字節)或BIGINT(佔用8個字節),指針 類型也通常爲4或8個字節,也就是說一個頁(B+Tree中的一個節點)中大概存儲16KB/(8B+8B)=1K個鍵值(由於 是估值,爲方便計算,這裏的K取值爲〖10〗^3)。也就是說一個深度爲3的B+Tree索引能夠維護10^3 * 10^3 * 10^3 = 10億 條記錄。
實際狀況中每一個節點可能不能填充滿,所以在數據庫中,B+Tree的高度通常都在2~4層。mysql的InnoDB存儲引擎 在設計時是將根節點常駐內存的,也就是說查找某一鍵值的行記錄時最多隻須要1~3次磁盤I/O操做。
數據庫中的B+Tree索引能夠分爲彙集索引(clustered index)和輔助索引(secondary index)。上面的B+Tree示 例圖在數據庫中的實現即爲彙集索引,彙集索引的B+Tree中的葉子節點存放的是整張表的行記錄數據。輔助索引與 彙集索引的區別在於輔助索引的葉子節點並不包含行記錄的所有數據,而是存儲相應行數據的彙集索引鍵,即主 鍵。當經過輔助索引來查詢數據時,InnoDB存儲引擎會遍歷輔助索引找到主鍵,而後再經過主鍵在彙集索引中找到 完整的行記錄數據
是最基本的索引,它沒有任何限制.
CREATE index 索引名 on 表名(列名)
複製代碼
與前面的普通索引相似,不一樣的就是:索引列的值必須惟一,但容許有空值。若是是組合索引,則列值的組合必須 惟一。
CREATE UNIQUE index 索引名 on 表名(列名)
複製代碼
是一種特殊的惟一索引,一個表只能有一個主鍵,不容許有空值。通常是在建表的時候同時建立主鍵索引.也就 是說主鍵約束默認索引
指多個字段上建立的索引,只有在查詢條件中使用了建立索引時的第一個字段,索引纔會被使用。使用組合索引時 遵循最左前綴集合
CREATE index 索引名 on 表名(列名,列名...)
複製代碼
主要用來查找文本中的關鍵字,而不是直接與索引中的值相比較。fulltext索引跟其它索引大不相同,它更像是一個 搜索引擎,而不是簡單的where語句的參數匹配。fulltext索引配合match against操做使用,而不是通常的where 語句加like。它能夠在create table,alter table ,create index使用,不過目前只有char、varchar,text 列上能夠 建立全文索引。值得一提的是,在數據量較大時候,現將數據放入一個沒有全局索引的表中,而後再用CREATE index建立fulltext索引,要比先爲一張表創建fulltext而後再將數據寫入的速度快不少
CREATE TABLE `table` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`title` char(255) CHARACTER NOT NULL ,
`content` text CHARACTER NULL ,
`time` int(10) NULL DEFAULT NULL ,
PRIMARY KEY (`id`), FULLTEXT (content)
);
複製代碼
ALTER mytable ADD [UNIQUE] INDEX [indexName] ON 表名(列名)
複製代碼
DROP INDEX [indexName] ON 表名;
複製代碼
SHOW INDEX FROM 表名
複製代碼
‐‐ 有四種方式來添加數據表的索引:
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list): 該語句添加一個主鍵,這意味着索引值必須是惟一的, 且不能爲NULL。
ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 這條語句建立索引的值必須是惟一的(除了NULL 外,NULL可能會出現屢次)。
ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出現屢次。
ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):該語句指定了索引爲 FULLTEXT ,用於全文索引。
複製代碼
MySQL Optimizer是一個專門負責優化SELECT 語句的優化器模塊,它主要的功能就是經過計算分析系統中收 集的各類統計信息,爲客戶端請求的Query 給出他認爲最優的執行計劃,也就是他認爲最優的數據檢索方式。
使用explain關鍵字能夠模擬優化器執行SQL查詢語句,從而知道MYSQL是如何處理SQL語句的.咱們能夠用執行 計劃來分析查詢語句或者表結構的性能瓶頸
explain sql語句
複製代碼
create table t1(
id int primary key,
name varchar(20),
col1 varchar(20),
col2 varchar(20),
col3 varchar(20)
);
create table t2(
id int primary key,
name varchar(20),
col1 varchar(20),
col2 varchar(20),
col3 varchar(20)
);
create table t3(
id int primary key,
name varchar(20),
col1 varchar(20),
col2 varchar(20),
col3 varchar(20)
);
insert into t1 values(1,'zs1','col1','col2','col3');
insert into t2 values(1,'zs2','col2','col2','col3');
insert into t3 values(1,'zs3','col3','col2','col3');
create index ind_t1_c1 on t1(col1);
create index ind_t2_c1 on t2(col1);
create index ind_t3_c1 on t3(col1);
create index ind_t1_c12 on t1(col1,col2);
create index ind_t2_c12 on t2(col1,col2);
create index ind_t3_c12 on t3(col1,col2);
複製代碼
select 查詢的序列號,包含一組數字,表示查詢中執行Select子句或操做表的順序
三種狀況:
explain select t2.* from t1,t2,t3 where t1.id = t2.id and t1.id= t3.id and t1.name = 'zs';
複製代碼
explain select t2.* from t2 where id = (select id from t1 where id = (select t3.id from t3 where t3.name='zs3'));
複製代碼
explain select t2.* from (select t3.id from t3 where t3.name='zs3') s1,t2 where s1.id = t2.id;
複製代碼
查詢類型,主要用於區別
explain select col1,col2 from t1 union select col1,col2 from t2;
複製代碼
顯示這一行的數據是和哪張表相關
訪問類型: all, index,range,ref,eq_ref, const,system,null
最好到最差依次是: system > const > eq_ref>ref >range > index > all , 最好能優化到range級別或則ref級別
explain select * from (select * from t1 where id=1) s1;
複製代碼
explain select * from t1,t2 where t1.id = t2.id;
複製代碼
explain select * from t1 where col1='zs1';
複製代碼
explain select * from t1 where id between 1 and 10;
複製代碼
explain select id from t1;
複製代碼
explain select * from t1;
複製代碼
SQL查詢中可能用到的索引,但查詢的過程當中不必定真正使用
查詢過程當中真正使用的索引,若是爲null,則表示沒有使用索引
查詢中使用了覆蓋索引,則該索引僅出如今key列表中
explain select t2.* from t1,t2,t3 where t1.col1 = ' ' and t1.id = t2.id and t1.id= t3.id;
複製代碼
explain select col1 from t1;
複製代碼
索引中使用的字節數,可經過該列計算查詢中使用的索引的長度,在不損失精確度的狀況下,長度越短越好, key_len顯 示的值爲索引字段的最大可能長度,並不是實際使用長度, 即key_len是根據表定義計算而得
explain select * from t1 where col1='c1';
複製代碼
explain select * from t1 where col1='col1' and col2 = 'col2';
‐‐ 注意: 爲了演示這個結果,咱們刪除了c1上面的索引
alter table t1 drop index ind_t1_c1;
‐‐ 執行完成以後,再次建立索引
create index ind_t1_c1 on t1(col1);
複製代碼
顯示索引的哪一列被使用了,若是可能的話,是一個常數.哪些列或者常量被用於查找索引列上的值
explain select * from t1,t2 where t1.col1 = t2.col1 and t1.col2 = 'col2';
複製代碼
根據表統計信息及索引選用的狀況,估算找出所需記錄要讀取的行數 (有多少行記錄被優化器讀取) ,越少越好
包含其它一些很是重要的額外信息
explain select col1 from t1 where col1='col1' order by col3;
複製代碼
‐‐ 上面這條SQL語句出現了using filesort,可是咱們去執行下面這條SQL語句的時候它,又不會出現using filesort
explain select col1 from t1 where col1='col1' order by col2;
複製代碼
‐‐ 如何優化第一條SQL語句 ?
create index ind_t1_c13 on t1(col1,col3);
explain select col1 from t1 where col1='col1' order by col3;
複製代碼
explain select col1 from t1 where col1>'col1' group by col2;
複製代碼
explain select col1 from t1 where col1 >'col1' group by col1,col2;
複製代碼
explain select col2 from t1 where col1='col1';
複製代碼
explain select col2 from t1;
複製代碼
explain select * from t1 where col1='zs' and col1='ls';
複製代碼
需求: 查詢 category_id 爲1 且 comments 大於 1 的狀況下,views 最多的 article_id。
CREATE TABLE IF NOT EXISTS `article` (
`id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`author_id` INT(10) UNSIGNED NOT NULL,
`category_id` INT(10) UNSIGNED NOT NULL,
`views` INT(10) UNSIGNED NOT NULL,
`comments` INT(10) UNSIGNED NOT NULL,
`title` VARBINARY(255) NOT NULL,
`content` TEXT NOT NULL
);
INSERT INTO `article`(`author_id`, `category_id`, `views`, `comments`, `title`, `content`) VALUES
(1, 1, 1, 1, '1', '1'),
(2, 2, 2, 2, '2', '2'),
(1, 1, 3, 3, '3', '3');
複製代碼
EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND comments > 1 ORDER BY views DESC LIMIT 1;
複製代碼
create index idx_article_ccv on article(category_id,comments,views);
複製代碼
結論: type 變成了 range,這是能夠忍受的。可是 extra 裏使用 Using filesort 還是沒法接受的。可是咱們已經創建 了索引,爲啥沒用呢? 這是由於按照 BTree 索引的工做原理, 先排序 category_id, 若是遇到相同的 category_id 則再 排序 comments,若是遇到相同的 comments 則再排序 views。當 comments 字段在聯合索引裏處於中間位置時,因 comments > 1 條件是一個範圍值(所謂 range),MySQL 沒法利用索引再對後面的 views 部分進行檢索,即 range 類 型查詢字段後面的索引無效。
‐‐ 先刪除優化一索引
DROP INDEX idx_article_ccv ON article;
‐‐ 建立索引
create index idx_article_cv on article(category_id,views);
複製代碼
需求: 使用左外鏈接查詢class和book
CREATE TABLE IF NOT EXISTS `class` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`card` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `book` (
`bookid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`card` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`bookid`)
);
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20))); INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
複製代碼
EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;
複製代碼
ALTER TABLE `book` ADD INDEX Y ( `card`);
複製代碼
能夠看到第二行的 type 變爲了 ref,rows 也變成了優化比較明顯。
這是由左鏈接特性決定的。LEFT JOIN 條件用於肯定如何從右表搜索行,左邊必定都有,因此右邊是咱們的關鍵點,必定 須要創建索引。
也就是說: 外鏈接在相反方建立索引
select a.name ,bc.name from t_emp a left join
(select b.id , c.name from t_dept b
inner join t_emp c on b.ceo = c.id)bc
on bc.id = a.deptid
上段查詢中用到了子查詢,必然 bc 表沒有索引。確定會進行全表掃描
上段查詢 能夠直接使用 兩個 left join 優化
select a.name , c.name from t_emp a
left outer join t_dept b on a.deptid = b.id
left outer join t_emp c on b.ceo=c.id
全部條件均可以使用到索引
若必須用到子查詢,可將子查詢設置爲驅動表,由於驅動表的type 確定是 all,而子查詢返回的結果表沒有索引,一定 也是all
複製代碼
CREATE TABLE tblA(
id int primary key not null auto_increment,
age INT,
birth TIMESTAMP NOT NULL,
name varchar(200)
);
INSERT INTO tblA(age,birth,name) VALUES(22,NOW(),'abc');
INSERT INTO tblA(age,birth,name) VALUES(23,NOW(),'bcd');
INSERT INTO tblA(age,birth,name) VALUES(24,NOW(),'def');
CREATE INDEX idx_A_ageBirth ON tblA(age,birth,name);
複製代碼
MySQL支持二種方式的排序,FileSort和Index,Index效率高. 它指MySQL掃描索引自己完成排序。FileSort方式效 率較低。
EXPLAIN SELECT * FROM tbla WHERE age > 1 ORDER BY age
複製代碼
EXPLAIN SELECT * FROM tbla WHERE age = 1 ORDER BY birth
複製代碼
group by實質是先排序後進行分組,遵守索引建的最佳左前綴
where高於having,能寫在where限定的條件就不要去having限定了
limit經常使用於分頁處理,時常會伴隨order by 從句使用, 所以大多時候會使用Filesorts,這樣會形成大量的IO問題