第1章 存儲引擎1.1 Mysql 邏輯架構介紹1.2 查看命令1.3 MyISAM 和 InnoDB 的對比1.4 阿里巴巴、淘寶用哪一個第2章 Join 查詢2.1 SQL 執行順序(通常狀況下)2.1.1 手寫順序2.1.2 機讀順序2.1.3 總結2.2 建表 SQL2.3 7 種 JOIN 圖2.4 7 種 JOIN 實操第3章 索引與數據處理3.1 索引是什麼3.1.1 索引的優點3.1.2 索引的劣勢3.2 索引分類3.3 查看執行計劃 -- Explain3.3.1 Explain 是什麼3.3.2 Explain 能幹嗎3.3.3 Explain 怎麼玩3.3.4 Explain 的各字段解釋3.4 小案例3.5 索引失效(應該避免)3.5.1 全值匹配我最愛(數量和順序全匹配)3.5.2 最佳左前綴法則3.5.3 不在索引列上作任何操做(計算、函數、(自動or手動)類型轉換),會致使索引失效而轉向全表掃描3.5.4 存儲引擎不能使用索引中範圍條件右邊的列3.5.5 儘可能使用覆蓋索引(只訪問索引的查詢(索引列和查詢列一致)),select * 儘可能少用3.5.6 mysql 在使用不等於(!= 或者<>)的時候,可能沒法使用索引會致使全表掃描3.5.7 注意 null/not null 對索引的可能影響,要看該字段是否認義爲空3.5.8 like 以通配符開頭('%abc…'),mysql 索引失效會變成全表掃描的操做3.5.9 字符串不加單引號索引失效3.5.10 少用 or,用它來鏈接時,索引可能會失效3.5.11 小總結3.6 批量數據腳本3.6.1 建表3.6.2 設置一個參數 log_bin_trust_function_creators3.6.3 建立函數,保證每條數據都不一樣3.6.4 建立存儲過程3.6.5 調用存儲過程html
天上飛的理念必有落地的實現。mysql
和其它數據庫相比,MySQL 有點不同凡響,它的架構能夠在多種不一樣場景中應用併發揮良好做用。主要體如今存儲引擎的架構
上,插件式的存儲引擎架構
將查詢處理和其它的系統任務以及數據的存儲提取相分離
。這種架構能夠根據業務的需求和實際須要選擇合適的存儲引擎。linux
一、鏈接層
最上層是一些客戶端和鏈接服務,包含本地 sock 通訊和大多數基於客戶端/服務端工具實現的相似於 tcp/ip 的通訊。主要完成一些相似於鏈接處理、受權認證、及相關的安全方案。在該層上引入了線程池的概念,爲經過認證安全接入的客戶端提供線程。一樣在該層上能夠實現基於 SSL 的安全連接。服務器也會爲安全接入的每一個客戶端驗證它所具備的操做權限。ios
二、服務層
第二層架構主要完成大多數的核心服務功能,如 SQL 接口,並完成緩存的查詢,SQL的分析和優化及部份內置函數的執行。全部跨存儲引擎的功能也在這一層實現,如過程、函數等。在該層,服務器會解析查詢並建立相應的內部解析樹,並對其完成相應的優化如肯定查詢表的順序,是否利用索引等,最後生成相應的執行操做。若是是 select 語句,服務器還會查詢內部的緩存。若是緩存空間足夠大,這樣在解決大量讀操做的環境中可以很好的提高系統的性能。算法
三、引擎層
存儲引擎層,存儲引擎真正的負責了 MySQL 中數據的存儲和提取,服務器經過 API 與存儲引擎進行通訊。不一樣的存儲引擎具備的功能不一樣,這樣咱們能夠根據本身的實際須要進行選取。後面主要介紹 MyISAM
和 InnoDB
。sql
四、存儲層
數據存儲層,主要是將數據存儲在運行於裸設備的文件系統之上,並完成與存儲引擎的交互。數據庫
如何用命令查看windows
#登陸客戶端
[atguigu@hadoop102 ~]$ mysql -uroot -p
#看你的 mysql 中的數據庫
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| commerce |
| company |
| db_telecom |
| metastore |
| mysql |
| oozie |
| performance_schema |
| rdd |
| report |
| test |
+--------------------+
#看你的 mysql 的版本
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.6.24 |
+-----------+
#建立數據庫
mysql> create database db0508;
Query OK, 1 row affected (0.00 sec)
#使用數據庫
mysql> use db0508;
Database changed
#看你的 mysql 的版本
#看你的 mysql 如今已提供什麼存儲引擎:
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
#看你的 mysql 當前默認的存儲引擎:
mysql> show variables like '%storage_engine%';
+----------------------------+--------+
| Variable_name | Value |
+----------------------------+--------+
| default_storage_engine | InnoDB |
| default_tmp_storage_engine | InnoDB |
| storage_engine | InnoDB |
+----------------------------+--------+
一、Percona 爲 MySQL 數據庫服務器進行了改進,在功能和性能上較 MySQL 有着很顯著的提高。該版本提高了在高負載狀況下的 InnoDB 的性能、爲 DBA 提供一些很是有用的性能診斷工具;另外有更多的參數和命令來控制服務器行爲。緩存
二、該公司新建了一款存儲引擎叫 xtradb 徹底能夠替代 innodb,而且在性能和併發上作得更好。安全
三、阿里巴巴大部分 mysql 數據庫其實使用的 percona 的原型加以修改。
四、AliSql + AliRedis
CREATE TABLE `tbl_dept` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`deptName` VARCHAR(30) DEFAULT NULL,
`locAdd` VARCHAR(40) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `tbl_emp` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) DEFAULT NULL,
`deptId` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_dept_id` (`deptId`)
#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `tbl_dept` (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO tbl_dept (deptName, locAdd) VALUES ('RD', 11);
INSERT INTO tbl_dept (deptName, locAdd) VALUES ('HR', 12);
INSERT INTO tbl_dept (deptName, locAdd) VALUES ('MK', 13);
INSERT INTO tbl_dept (deptName, locAdd) VALUES ('MIS', 14);
INSERT INTO tbl_dept (deptName, locAdd) VALUES ('FD', 15);
INSERT INTO tbl_emp (NAME, deptId) VALUES ('z3', 1);
INSERT INTO tbl_emp (NAME, deptId) VALUES ('z4', 1);
INSERT INTO tbl_emp (NAME, deptId) VALUES ('z5', 1);
INSERT INTO tbl_emp (NAME, deptId) VALUES ('w5', 2);
INSERT INTO tbl_emp (NAME, deptId) VALUES ('w6', 2);
INSERT INTO tbl_emp (NAME, deptId) VALUES ('s7', 3);
INSERT INTO tbl_emp (NAME, deptId) VALUES ('s8', 4);
INSERT INTO tbl_emp (NAME, deptId) VALUES ('s9', 51);
0:原始數據
mysql> select * from tbl_emp;
+----+------+--------+
| id | name | deptId |
+----+------+--------+
| 1 | z3 | 1 |
| 2 | z4 | 1 |
| 3 | z5 | 1 |
| 4 | w5 | 2 |
| 5 | w6 | 2 |
| 6 | s7 | 3 |
| 7 | s8 | 4 |
| 8 | s9 | 51 |
+----+------+--------+
8 rows in set (0.00 sec)
mysql> select * from tbl_dept;
+----+----------+--------+
| id | deptName | locAdd |
+----+----------+--------+
| 1 | RD | 11 |
| 2 | HR | 12 |
| 3 | MK | 13 |
| 4 | MIS | 14 |
| 5 | FD | 15 |
+----+----------+--------+
5 rows in set (0.00 sec)
1:A、B 兩表共有
mysql> select * from tbl_emp a inner join tbl_dept b on a.deptId = b.id;
+----+------+--------+----+----------+--------+
| id | name | deptId | id | deptName | locAdd |
+----+------+--------+----+----------+--------+
| 1 | z3 | 1 | 1 | RD | 11 |
| 2 | z4 | 1 | 1 | RD | 11 |
| 3 | z5 | 1 | 1 | RD | 11 |
| 4 | w5 | 2 | 2 | HR | 12 |
| 5 | w6 | 2 | 2 | HR | 12 |
| 6 | s7 | 3 | 3 | MK | 13 |
| 7 | s8 | 4 | 4 | MIS | 14 |
+----+------+--------+----+----------+--------+
7 rows in set (0.00 sec)
2:A、B 兩表共有 +A 的獨有
mysql> select * from tbl_emp a left join tbl_dept b on a.deptId = b.id;
+----+------+--------+------+----------+--------+
| id | name | deptId | id | deptName | locAdd |
+----+------+--------+------+----------+--------+
| 1 | z3 | 1 | 1 | RD | 11 |
| 2 | z4 | 1 | 1 | RD | 11 |
| 3 | z5 | 1 | 1 | RD | 11 |
| 4 | w5 | 2 | 2 | HR | 12 |
| 5 | w6 | 2 | 2 | HR | 12 |
| 6 | s7 | 3 | 3 | MK | 13 |
| 7 | s8 | 4 | 4 | MIS | 14 |
| 8 | s9 | 51 | NULL | NULL | NULL |
+----+------+--------+------+----------+--------+
3:A、B 兩表共有 +B 的獨有
mysql> select * from tbl_emp a right join tbl_dept b on a.deptId = b.id;
+------+------+--------+----+----------+--------+
| id | name | deptId | id | deptName | locAdd |
+------+------+--------+----+----------+--------+
| 1 | z3 | 1 | 1 | RD | 11 |
| 2 | z4 | 1 | 1 | RD | 11 |
| 3 | z5 | 1 | 1 | RD | 11 |
| 4 | w5 | 2 | 2 | HR | 12 |
| 5 | w6 | 2 | 2 | HR | 12 |
| 6 | s7 | 3 | 3 | MK | 13 |
| 7 | s8 | 4 | 4 | MIS | 14 |
| NULL | NULL | NULL | 5 | FD | 15 |
+------+------+--------+----+----------+--------+
8 rows in set (0.00 sec)
4:A 的獨有
mysql> select * from tbl_emp a left join tbl_dept b on a.deptId = b.id where b.id is null;
+----+------+--------+------+----------+--------+
| id | name | deptId | id | deptName | locAdd |
+----+------+--------+------+----------+--------+
| 8 | s9 | 51 | NULL | NULL | NULL |
+----+------+--------+------+----------+--------+
1 row in set (0.00 sec)
5:B 的獨有
mysql> select * from tbl_emp a right join tbl_dept b on a.deptId = b.id where a.id is null;
+------+------+--------+----+----------+--------+
| id | name | deptId | id | deptName | locAdd |
+------+------+--------+----+----------+--------+
| NULL | NULL | NULL | 5 | FD | 15 |
+------+------+--------+----+----------+--------+
1 row in set (0.00 sec)
6:AB 全有
mysql> select * from tbl_emp a left join tbl_dept b on a.deptId = b.id
-> union
-> select * from tbl_emp a right join tbl_dept b on a.deptId = b.id;
+------+------+--------+------+----------+--------+
| id | name | deptId | id | deptName | locAdd |
+------+------+--------+------+----------+--------+
| 1 | z3 | 1 | 1 | RD | 11 |
| 2 | z4 | 1 | 1 | RD | 11 |
| 3 | z5 | 1 | 1 | RD | 11 |
| 4 | w5 | 2 | 2 | HR | 12 |
| 5 | w6 | 2 | 2 | HR | 12 |
| 6 | s7 | 3 | 3 | MK | 13 |
| 7 | s8 | 4 | 4 | MIS | 14 |
| 8 | s9 | 51 | NULL | NULL | NULL |
| NULL | NULL | NULL | 5 | FD | 15 |
+------+------+--------+------+----------+--------+
9 rows in set (0.00 sec)
7:A 的獨有 +B 的獨有
mysql> select * from tbl_emp a left join tbl_dept b on a.deptId = b.id where b.id is null
-> union
-> select * from tbl_emp a right join tbl_dept b on a.deptId = b.id where a.deptId is null;
+------+------+--------+------+----------+--------+
| id | name | deptId | id | deptName | locAdd |
+------+------+--------+------+----------+--------+
| 8 | s9 | 51 | NULL | NULL | NULL |
| NULL | NULL | NULL | 5 | FD | 15 |
+------+------+--------+------+----------+--------+
2 rows in set (0.00 sec)
小結:
1:A、B 兩表共有
select * from tbl_emp a inner join tbl_dept b on a.deptId = b.id;
2:A、B 兩表共有 +A 的獨有
select * from tbl_emp a left join tbl_dept b on a.deptId = b.id;
3:A、B 兩表共有 +B 的獨有
select * from tbl_emp a right join tbl_dept b on a.deptId = b.id;
4:A 的獨有
select * from tbl_emp a left join tbl_dept b on a.deptId = b.id where b.id is null;
5:B 的獨有
select * from tbl_emp a right join tbl_dept b on a.deptId = b.id where a.deptId is null; #B的獨有
6:AB 全有
#MySQL Full Join 的實現:由於 MySQL 不支持 FULL JOIN,下面是替代方法
#left join + union(可去除重複數據)+ right join
SELECT * FROM tbl_emp A LEFT JOIN tbl_dept B ON A.deptId = B.id
UNION
SELECT * FROM tbl_emp A RIGHT JOIN tbl_dept B ON A.deptId = B.id
7:A 的獨有 +B 的獨有
SELECT * FROM tbl_emp A LEFT JOIN tbl_dept B ON A.deptId = B.id WHERE B.`id` IS NULL
UNION
SELECT * FROM tbl_emp A RIGHT JOIN tbl_dept B ON A.deptId = B.id WHERE A.`deptId` IS NULL;
MySQL 官方對索引的定義爲:索引(Index)是幫助 MySQL 高效獲取數據的數據結構。能夠獲得索引的本質:索引是數據結構
。
索引的目的在於提升查詢效率,能夠類比字典,若是要查 「mysql」 這個單詞,咱們確定須要定位到 m 字母,而後從下往下找到 y 字母,再找到剩下的 sql。若是沒有索引,那麼你可能須要 a----z,若是我想找到 Java 開頭的單詞呢?或者 Oracle 開頭的單詞呢?是否是以爲若是沒有索引,這個事情根本沒法完成?
你能夠簡單理解爲「排好序的快速查找數據結構」
。圖書館 -- 圖書管理員(索引) -- 書
在數據以外,數據庫系統還維護着知足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就能夠在這些數據結構上實現高級查找算法。這種數據結構,就是索引。
下圖就是一種可能的索引方式示例:
左邊是數據表,一共有兩列七條記錄,最左邊的是數據記錄的物理地址,爲了加快 Col2 的查找,能夠維護一個右邊所示的二叉查找樹,每一個節點分別包含索引鍵值和一個指向對應數據記錄物理地址的指針
,這樣就能夠運用二叉查找在必定的複雜度內獲取到相應數據,從而快速的檢索出符合條件的記錄。
索引的數據結構是 BTree。(b-tree 就是 BTree、b+tree、b*tree)
通常來講索引自己也很大,不可能所有存儲在內存中,所以索引每每以索引文件的形式存儲的磁盤上。咱們日常所說的索引,若是沒有特別指明,都是指 B 樹(多路搜索樹,並不必定是二叉的)結構組織的索引。
BTREE,B 樹(Balance Tree 多路平衡查找樹)
。
相似大學圖書館建書目索引,提升數據檢索的效率,下降數據庫的 IO 成本。(如何用 Linux 命令查看 IO:iostat -d 2 3 每兩秒鐘取一次,共取三次)
經過索引列對數據進行排序,下降數據排序的成本,下降了 CPU 的消耗。(如何用 Linux 命令查看 CPU:vmstat -n 2 3 每兩秒鐘取一次,共取三次)
數據庫 sql 慢,表如今兩個硬件方面:檢索慢(IO 多)、排序慢(CPU 慢)。
[atguigu@hadoop102 ~]$ iostat -d 2 3
Linux 2.6.32-642.el6.x86_64 (hadoop102) 2019年06月11日 _x86_64_ (4 CPU)
Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn
sda 1.88 65.06 5.83 709528 63594
Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn
sda 0.00 0.00 0.00 0 0
Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn
sda 0.00 0.00 0.00 0 0
[atguigu@hadoop102 ~]$ vmstat -n 2 3
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 2851536 182004 171732 0 0 8 1 16 24 0 0 100 0 0
0 0 0 2851520 182004 171760 0 0 0 0 72 99 0 0 100 0 0
0 0 0 2851560 182004 171760 0 0 0 0 64 96 0 0 100 0 0
實際上索引也是一張表,該表保存了主鍵與索引字段,並指向實體表的記錄,因此索引列也是要佔用空間的。
雖然索引大大提升了查詢速度,同時卻會下降更新表的速度,如對錶進行 INSERT、UPDATE 和 DELETE。由於更新表時,MySQL 不只要保存數據,還要保存一下索引文件每次更新添加了索引列的字段,都會調整由於更新所帶來的鍵值變化後的索引信息。
索引只是提升效率的一個因素,若是你的 MySQL 有大數據量的表,就須要花時間研究創建最優秀的索引,或優化查詢語句。
小示例
使用 EXPLAIN 關鍵字能夠模擬優化器執行 SQL 查詢語句,從而知道 MySQL 是如何處理你的 SQL 語句的。分析你的查詢語句或是表結構的性能瓶頸。
官網 http://dev.mysql.com/doc/refman/5.5/en/explain-output.html
一、id(重要)
id 是 select 查詢的序列號, 包含一組數字,表示查詢中執行 select 子句或操做表的順序。
第一種狀況:id 相同,執行順序由上至下
第二種狀況:id 不一樣,若是是子查詢,id 的序號會遞增,id 值越大優先級越高,越先被執行
第三種狀況:id 相同又不一樣,同時存在。id 若是相同,能夠認爲是一組,從上往下順序執行;在全部組中,id 值越大,優先級越高,越先執行。衍生 = DERIVED
二、select_type
查詢類型詳解:
三、table
顯示這一行的數據是關於哪張表的。
四、type(重要)
顯示查詢使用了何種類型。
type 顯示的是訪問類型,是較爲重要的一個指標,結果值從最好到最壞依次是:
全部的訪問類型:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
經常使用的訪問類型:system > const > eq_ref > ref > range > index > ALL
通常來講,咱們公司得保證查詢至少達到 range 級別,最好能達到 ref
。若是出現了 type 出現了 ALL,須要進行路徑的尋址、sql 的優化和索引的創建。
顯示查詢使用了何種類型
從最好到最差依次是:system > const > eq_ref > ref > range > index > ALL
五、possible_keys
六、key
七、key_len
表示索引中使用的字節數,可經過該列計算查詢中使用的索引的長度。在不損失精確性的狀況下,長度越短越好。
key_len
顯示的值爲索引字段的最大可能長度,並不是實際使用長度,即 key_len
是根據表定義計算而得,不是經過表內檢索出的。
難點:如何計算的?
key_len:數據庫版本 + 存儲引擎 + 定義的字段類型 + 定義的字段是否能夠 null + 字符集編碼
都會影響到 key_len 的使用和計算參考值。
例如:5.6.24 + InnoDB + char(4) + null + utf-8
數據類型長度
數值類型
計算方法估值表
key_len 表示索引使用的字節數,根據這個值,就能夠判斷索引使用狀況,特別是在組合索引的時候,判斷全部的索引字段是否都被查詢用到。
char 和 varchar 跟字符編碼也有密切的聯繫,
latin1 佔用 1 個字節,gbk 佔用 2 個字節,utf8 佔用 3 個字節。(不一樣字符編碼佔用的存儲空間不一樣)
案例演示
字符型
(1) 字符型:索引字段爲 char 類型 + 不可爲 Null 時
(2) 字符型:索引字段爲 char 類型 + 容許爲 Null 時
(3) 字符型:索引字段爲 varchar 類型 + 不可爲 Null 時
(4) 字符型:索引字段爲 varchar 類型 + 容許爲 Null 時
整數/浮點數/時間類型的索引長度
NOT NULL=字段自己的字段長度
NULL=字段自己的字段長度 + 1(由於須要有是否爲空的標記,這個標記須要佔用 1 個字節)
注意
:datetime 類型在 5.6 中字段長度是 5 個字節,datetime 類型在 5.5 中字段長度是8個字節。
小總結
變長字段須要額外的 2 個字節(VARCHAR 值保存時只保存須要的字符數,另加一個字節來記錄長度(若是列聲明的長度超過 255,則使用兩個字節),因此 VARCAHR 索引長度計算時候要加 2),固定長度字段不須要額外的字節。
而 NULL 都須要 1 個字節的額外空間,因此索引字段最好不要爲 NULL,由於 NULL 讓統計更加複雜而且須要額外的存儲空間
。
因此,複合索引有最左前綴的特性
,若是複合索引能所有使用上,則是複合索引字段的索引長度之和,這也能夠用來斷定複合索引是否部分使用,仍是所有使用。
八、ref
顯示索引的哪一列被使用了,若是可能的話,是一個常量。哪些列或常量被用於查找索引列上的值。
key_len
可知 t1 表的 idx_col1_col2 被充分使用,col1 匹配 t2 表的 col1,col2 匹配了一個常量,即 'ac'。
九、rows
根據表統計信息及索引選用狀況,大體估算出找到所需的記錄所須要讀取的行數。
十、Extra
包含不適合在其餘列中顯示但十分重要的額外信息。
(1) Using filesort
說明 mysql 會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。
即你的 order by 的順序沒有複用索引的創建順序,沒有保持一致。
MySQL 中沒法利用索引完成的排序操做稱爲 「文件排序」。
查詢中排序的字段
和 排序中的排序字段
若經過索引去訪問將大大提升排序速度。
(2) Using temporary
使了用臨時表保存中間結果,MySQL 在對查詢結果排序時使用臨時表。常見於排序 order by 和分組查詢 group by。
(3) Using index
表示相應的 select 操做中使用了覆蓋索引(Covering Index)
,避免訪問了表的數據行,效率不錯!
若是同時出現 Using where,代表索引被用來執行索引鍵值的查找。
若是沒有同時出現 Using where,代表索引用來讀取數據而非執行查找動做。
覆蓋索引(Covering Index),一說爲索引覆蓋。
理解方式一:就是 select 的數據列只用從索引中就可以取得,沒必要讀取數據行,MySQL 能夠利用索引返回 select 列表中的字段,而沒必要根據索引再次讀取數據文件,換句話說查詢列要被所建的索引覆蓋
。
理解方式二:索引是高效找到行的一個方法,可是通常數據庫也能使用索引找到一個列的數據,所以它沒必要讀取整個行。畢竟索引葉子節點存儲了它們索引的數據;當能經過讀取索引就能夠獲得想要的數據,那就不須要讀取行了。一個索引包含了(或覆蓋了)知足查詢結果的數據就叫作覆蓋索引。注意
:
若是要使用覆蓋索引,必定要注意 select 列表中只取出須要的列,不可用 select *,由於若是將全部字段一塊兒作索引會致使索引文件過大,查詢性能降低。(通常建索引的字段的個數是 3 到 5 個。)
(4) Using where
表示使用了 where 過濾。
(5) Using join buffer
表示使用了鏈接緩存。
(6) Impossible where
where 子句的值老是 false,不能用來獲取任何元組。
建表 SQL
CREATE TABLE staffs (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR (24) NOT NULL DEFAULT '' COMMENT '姓名',
age INT NOT NULL DEFAULT 0 COMMENT '年齡',
pos VARCHAR (20) NOT NULL DEFAULT '' COMMENT '職位',
add_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入職時間'
) CHARSET utf8 COMMENT '員工記錄表' ;
INSERT INTO staffs (NAME,age,pos,add_time) VALUES ('z3',22,'manager',NOW());
INSERT INTO staffs (NAME,age,pos,add_time) VALUES ('July',23,'dev',NOW());
INSERT INTO staffs (NAME,age,pos,add_time) VALUES ('2000',24,'dev',NOW());
INSERT INTO staffs (NAME,age,pos,add_time) VALUES ('3000',26,'dev',NOW());
SELECT * FROM staffs;
ALTER TABLE staffs ADD INDEX idx_staffs_nameAgePos(name, age, pos);
若是索引了多列,要遵照最左前綴法則。指的是查詢從索引的最左前列開始而且不跳過索引中的列
。
即等號左邊不要有計算、函數、(自動or手動)類型轉換。
狀況一:
CREATE TABLE staffs (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR (24) NOT NULL DEFAULT '' COMMENT '姓名',
age INT NOT NULL DEFAULT 0 COMMENT '年齡',
pos VARCHAR (20) NOT NULL DEFAULT '' COMMENT '職位',
add_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入職時間'
) CHARSET utf8 COMMENT '員工記錄表' ;
INSERT INTO staffs (NAME, age, pos, add_time) VALUES ('z3', 22, 'manager', NOW());
ALTER TABLE staffs ADD INDEX idx_staffs_nameAgePos(NAME, age, pos);
ALTER TABLE staffs ADD INDEX idx_staffs_name (NAME);
EXPLAIN SELECT * FROM staffs WHERE NAME IS NULL;
EXPLAIN SELECT * FROM staffs WHERE NAME IS NOT NULL;
狀況二:
CREATE TABLE staffs2 (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR (24),
age INT NOT NULL DEFAULT 0 COMMENT '年齡',
pos VARCHAR (20) NOT NULL DEFAULT '' COMMENT '職位',
add_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入職時間'
) CHARSET utf8 COMMENT '員工記錄表' ;
INSERT INTO staffs2 (NAME, age, pos, add_time) VALUES ('z3', 22, 'manager', NOW());
ALTER TABLE staffs2 ADD INDEX idx_staffs2_nameAgePos (NAME, age, pos);
ALTER TABLE staffs2 ADD INDEX idx_staffs2_name (NAME);
EXPLAIN SELECT * FROM staffs2 WHERE NAME IS NULL;
EXPLAIN SELECT * FROM staffs2 WHERE NAME IS NOT NULL;
CREATE TABLE `tbl_user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`NAME` VARCHAR(20) DEFAULT NULL,
`age` INT(11) DEFAULT NULL,
email VARCHAR(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
#drop table tbl_user
INSERT INTO tbl_user (NAME,age,email) VALUES ('1aa1',21,'b@163.com');
INSERT INTO tbl_user (NAME,age,email) VALUES ('2aa2',222,'a@163.com');
INSERT INTO tbl_user (NAME,age,email) VALUES ('3aa3',265,'c@163.com');
INSERT INTO tbl_user (NAME,age,email) VALUES ('4aa4',21,'d@163.com');
INSERT INTO tbl_user (NAME,age,email) VALUES ('aa',121,'e@163.com');
#before index
EXPLAIN SELECT NAME, age FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT id FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT NAME FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT age FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT id, NAME FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT id, NAME, age FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT NAME, age FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT * FROM tbl_user WHERE NAME LIKE '%aa%';
EXPLAIN SELECT id, NAME, age, email FROM tbl_user WHERE NAME LIKE '%aa%';
#create index
CREATE INDEX idx_user_nameAge ON tbl_user (NAME,age);
#delete index
DROP INDEX idx_user_nameAge ON tbl_user;
#after index
EXPLAIN SELECT * FROM tbl_user WHERE NAME =800 AND age = 33;
若是數據量小,能夠用 or
若是數據量巨大,or 使用 UNION ALL 進行進行替換
後面還有:挖掘技術看藍翔,IT/DT技術學尚硅谷!
往表裏插入 1000W 數據
測試腳本以下:
# 新建庫
create database bigData0508;
use bigData0508;
#1 建表 dept
CREATE TABLE dept(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
dname VARCHAR(20) NOT NULL DEFAULT "",
loc VARCHAR(13) NOT NULL DEFAULT ""
) ENGINE=INNODB DEFAULT CHARSET=GBK;
#2 建表 emp
CREATE TABLE emp (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
empno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*編號*/
ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/
job VARCHAR(9) NOT NULL DEFAULT "",/*工做*/
mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上級編號*/
hiredate DATE NOT NULL,/*入職時間*/
sal DECIMAL(7,2) NOT NULL,/*薪水*/
comm DECIMAL(7,2) NOT NULL,/*紅利*/
deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部門編號*/
)ENGINE=INNODB DEFAULT CHARSET=GBK;
爲何要設置這個參數?
答:當開啓二進制日誌後(能夠執行 show variables like 'log_bin_trust_function_creators'
查看是否開啓),若是變量 log_bin_trust_function_creators 爲 OFF,那麼建立或修改存儲函數就會報以下的錯誤:
「ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)」
【解決方法】
# 臨時設置的方式:
show variables like 'log_bin_trust_function_creators';
set global log_bin_trust_function_creators=1;
# 這樣添加了參數之後,若是 mysqld 重啓,上述參數又會消失,永久設置的方式:
windows 下 my.ini[mysqld] 加上 log_bin_trust_function_creators=1
linux下 /etc/my.cnf 下 my.cnf[mysqld] 加上 log_bin_trust_function_creators=1
官網解釋以下:
(1) 隨機產生字符串
DELIMITER $$
CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)
BEGIN
DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
DECLARE return_str VARCHAR(255) DEFAULT '';
DECLARE i INT DEFAULT 0;
WHILE i < n DO
SET return_str =CONCAT(return_str, SUBSTRING(chars_str, FLOOR(1+RAND()*52), 1));
SET i = i + 1;
END WHILE;
RETURN return_str;
END $$
#假如要刪除
#DROP function rand_string;
(2) 隨機產生部門編號
#用於隨機產生部門編號
DELIMITER $$
CREATE FUNCTION rand_num( )
RETURNS INT(5)
BEGIN
DECLARE i INT DEFAULT 0;
SET i = FLOOR(100 + RAND()*10);
RETURN i;
END $$
#假如要刪除
#DROP function rand_num;
(1) 建立往 emp 表中插入數據的存儲過程
DELIMITER $$
CREATE PROCEDURE insert_emp(IN START INT(10), IN max_num INT(10))
BEGIN
DECLARE i INT DEFAULT 0;
#set autocommit =0 把 autocommit 設置成 0
SET autocommit = 0;
REPEAT
SET i = i + 1;
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES ((START+i), rand_string(6), 'SALESMAN', 0001, CURDATE(), 2000, 400, rand_num());
UNTIL i = max_num
END REPEAT;
COMMIT;
END $$
#刪除
DELIMITER ;
DROP PROCEDURE insert_emp;
(2) 建立往 dept 表中插入數據的存儲過程
DELIMITER $$
CREATE PROCEDURE insert_dept(IN START INT(10), IN max_num INT(10))
BEGIN
DECLARE i INT DEFAULT 0;
SET autocommit = 0;
REPEAT
SET i = i + 1;
INSERT INTO dept (deptno, dname, loc) VALUES ((START+i), rand_string(10), rand_string(8));
UNTIL i = max_num
END REPEAT;
COMMIT;
END $$
#刪除
DELIMITER ;
DROP PROCEDURE insert_dept;
執行存儲過程,往 dept 表添加 10 條數據
DELIMITER ;
CALL insert_dept(100, 10);
查看
select * from dept limit 10;
執行存儲過程,往 emp 表添加 50 萬條數據
DELIMITER ;
CALL insert_emp(100001, 500000);
查看
select * from emp limit 200;