@(MySQL學習)
文章目錄
一. 哪張原數據表中記錄了Cardinality信息
--
-- 在information_schema.STATISTICS中記錄了相關的信息
--
mysql> use information_schema;
Database changed
mysql> show create table STATISTICS\G
*************************** 1. row ***************************
Table: STATISTICS
Create Table: CREATE TEMPORARY TABLE `STATISTICS` (
`TABLE_CATALOG` varchar(512) NOT NULL DEFAULT '',
`TABLE_SCHEMA` varchar(64) NOT NULL DEFAULT '', -- 表所在的庫
`TABLE_NAME` varchar(64) NOT NULL DEFAULT '', -- 表名
`NON_UNIQUE` bigint(1) NOT NULL DEFAULT '0',
`INDEX_SCHEMA` varchar(64) NOT NULL DEFAULT '',
`INDEX_NAME` varchar(64) NOT NULL DEFAULT '', -- 索引名
`SEQ_IN_INDEX` bigint(2) NOT NULL DEFAULT '0', -- 索引的序號
`COLUMN_NAME` varchar(64) NOT NULL DEFAULT '',
`COLLATION` varchar(1) DEFAULT NULL,
`CARDINALITY` bigint(21) DEFAULT NULL, -- 這裏我們找到了Cardinality
`SUB_PART` bigint(3) DEFAULT NULL,
`PACKED` varchar(10) DEFAULT NULL,
`NULLABLE` varchar(3) NOT NULL DEFAULT '',
`INDEX_TYPE` varchar(16) NOT NULL DEFAULT '',
`COMMENT` varchar(16) DEFAULT NULL,
`INDEX_COMMENT` varchar(1024) NOT NULL DEFAULT ''
) ENGINE=MEMORY DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
--
-- 之前我們可以通過 show index from table_name的方式查看索引
--
mysql> show index from employees.salaries\G
*************************** 1. row ***************************
Table: salaries
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1 -- 索引序號爲1
Column_name: emp_no
Collation: A
Cardinality: 286271 -- Cardinality值
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 2. row ***************************
Table: salaries
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 2 -- 索引序號爲2
Column_name: from_date
Collation: A
Cardinality: 2760952 -- Cardinality值
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
2 rows in set (0.00 sec)
--
-- 現在可以通過STATISTICS表查看某張表的信息
--
mysql> select * from STATISTICS where table_name='salaries'\G
*************************** 1. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: employees
TABLE_NAME: salaries
NON_UNIQUE: 0
INDEX_SCHEMA: employees
INDEX_NAME: PRIMARY
SEQ_IN_INDEX: 1 -- 索引序號爲1
COLUMN_NAME: emp_no
COLLATION: A
CARDINALITY: 286271 -- Cardinality值
SUB_PART: NULL
PACKED: NULL
NULLABLE:
INDEX_TYPE: BTREE
COMMENT:
INDEX_COMMENT:
*************************** 2. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: employees
TABLE_NAME: salaries
NON_UNIQUE: 0
INDEX_SCHEMA: employees
INDEX_NAME: PRIMARY
SEQ_IN_INDEX: 2 -- 索引序號爲2
COLUMN_NAME: from_date
COLLATION: A
CARDINALITY: 2760952 -- Cardinality值
SUB_PART: NULL
PACKED: NULL
NULLABLE:
INDEX_TYPE: BTREE
COMMENT:
INDEX_COMMENT:
2 rows in set (0.00 sec)
---
--- 可以看出,上面兩個方法得到的Cardinality的值是相等
--- 結論就是information_schema.STATISTICS這張表記錄了Cardinality信息
---
- 檢查表的索引創建的情況,判斷該索引是否有創建的必要
--
-- 1. 表的信息如table_schema, table_name, table_rows等
-- 在information_schema.TABLES中
--
mysql> show create table TABLES\G
*************************** 1. row ***************************
Table: TABLES
Create Table: CREATE TEMPORARY TABLE `TABLES` (
`TABLE_CATALOG` varchar(512) NOT NULL DEFAULT '',
`TABLE_SCHEMA` varchar(64) NOT NULL DEFAULT '', -- 表所在的庫
`TABLE_NAME` varchar(64) NOT NULL DEFAULT '', -- 表名
`TABLE_TYPE` varchar(64) NOT NULL DEFAULT '',
`ENGINE` varchar(64) DEFAULT NULL,
`VERSION` bigint(21) unsigned DEFAULT NULL,
`ROW_FORMAT` varchar(10) DEFAULT NULL,
`TABLE_ROWS` bigint(21) unsigned DEFAULT NULL, -- 表的記錄數
`AVG_ROW_LENGTH` bigint(21) unsigned DEFAULT NULL,
`DATA_LENGTH` bigint(21) unsigned DEFAULT NULL,
`MAX_DATA_LENGTH` bigint(21) unsigned DEFAULT NULL,
`INDEX_LENGTH` bigint(21) unsigned DEFAULT NULL,
`DATA_FREE` bigint(21) unsigned DEFAULT NULL,
`AUTO_INCREMENT` bigint(21) unsigned DEFAULT NULL,
`CREATE_TIME` datetime DEFAULT NULL,
`UPDATE_TIME` datetime DEFAULT NULL,
`CHECK_TIME` datetime DEFAULT NULL,
`TABLE_COLLATION` varchar(32) DEFAULT NULL,
`CHECKSUM` bigint(21) unsigned DEFAULT NULL,
`CREATE_OPTIONS` varchar(255) DEFAULT NULL,
`TABLE_COMMENT` varchar(2048) NOT NULL DEFAULT ''
) ENGINE=MEMORY DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
--
-- 2. information.STATISTICS中存在 table_schema 和 table_name 信息
--
mysql> show create table STATISTICS\G
*************************** 1. row ***************************
Table: STATISTICS
Create Table: CREATE TEMPORARY TABLE `STATISTICS` (
`TABLE_CATALOG` varchar(512) NOT NULL DEFAULT '',
`TABLE_SCHEMA` varchar(64) NOT NULL DEFAULT '', -- 表所在的庫
`TABLE_NAME` varchar(64) NOT NULL DEFAULT '', -- 表名
`NON_UNIQUE` bigint(1) NOT NULL DEFAULT '0',
`INDEX_SCHEMA` varchar(64) NOT NULL DEFAULT '',
`INDEX_NAME` varchar(64) NOT NULL DEFAULT '', -- 索引名
`SEQ_IN_INDEX` bigint(2) NOT NULL DEFAULT '0',
`COLUMN_NAME` varchar(64) NOT NULL DEFAULT '',
`COLLATION` varchar(1) DEFAULT NULL,
`CARDINALITY` bigint(21) DEFAULT NULL,
`SUB_PART` bigint(3) DEFAULT NULL,
`PACKED` varchar(10) DEFAULT NULL,
`NULLABLE` varchar(3) NOT NULL DEFAULT '',
`INDEX_TYPE` varchar(16) NOT NULL DEFAULT '',
`COMMENT` varchar(16) DEFAULT NULL,
`INDEX_COMMENT` varchar(1024) NOT NULL DEFAULT ''
) ENGINE=MEMORY DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
--
-- 3. 將TABLES 和 STATISTICS 表中的table_schema和table_name相關聯
-- 通過Cardinality和table_rows 計算,即可得到對應索引名的 選擇性
--
--
-- 3.1 因爲存在複合索引,所以我們要取出複合索引中seq最大的哪個值
-- 這樣取出的cardinality值纔是最大的
--
mysql> select
-> table_schema, table_name, index_name,
-> max(seq_in_index) -- 取出最大的seq號後,選出index_name等信息
-> from
-> STATISTICS
-> group by table_schema , table_name , index_name\G
-- -----------省略其他輸出-----------
*************************** 10. row ***************************
table_schema: burn_test
table_name: test_index_2
index_name: idx_mul_ab -- 這個是上次測試複合索引建立的index
max(seq_in_index): 2 -- 取出了最大的seq
-- -----------省略其他輸出-----------
--
-- 3.2 得到了最大的seq,從而可以取出對應的cardinality
--
mysql> select
-> table_schema, table_name, index_name, cardinality
-> from
-> STATISTICS
-> where
-> (table_schema , table_name, index_name, seq_in_index) in
-> (select
-> table_schema, table_name,
-> index_name, max(seq_in_index)
-> from
-> STATISTICS
-> group by table_schema , table_name , index_name)\G
*************************** 1. row ***************************
table_schema: burn_test
table_name: Orders
index_name: PRIMARY
cardinality: 5
*************************** 2. row ***************************
table_schema: burn_test
table_name: Orders_MV
index_name: product_name
cardinality: 3
*************************** 3. row ***************************
table_schema: burn_test
table_name: child
index_name: par_ind
cardinality: 0
*************************** 4. row ***************************
table_schema: burn_test
table_name: parent
index_name: PRIMARY
cardinality: 1
*************************** 5. row ***************************
table_schema: burn_test
table_name: t4
index_name: PRIMARY
cardinality: 4
-- -----------省略其他輸出-----------
--
-- 3.3 最後通過table_schema和table_name 讓上述的信息和TABLES表進行關聯
--
SELECT
t.TABLE_SCHEMA,t.TABLE_NAME,INDEX_NAME, CARDINALITY, TABLE_ROWS,
CARDINALITY/TABLE_ROWS AS SELECTIVITY -- 得到選擇性
FROM
TABLES t, -- 查詢的表一,TABLES
(
SELECT
table_schema,
table_name,
index_name,
cardinality
FROM STATISTICS
WHERE (table_schema,table_name,index_name,seq_in_index) IN (
SELECT
table_schema,
table_name,
index_name,
MAX(seq_in_index)
FROM
STATISTICS
GROUP BY table_schema , table_name , index_name )
) s -- 查詢的表二,就是上面3.2的查詢結果
WHERE
t.table_schema = s.table_schema -- 通過庫關聯
AND t.table_name = s.table_name -- 再通過表變量
AND t.table_schema = 'employees' -- 指定某一個庫名
ORDER BY SELECTIVITY;
+--------------+--------------+------------+-------------+------------+------------+
| TABLE_SCHEMA | TABLE_NAME | index_name | cardinality | TABLE_ROWS | SELECTIVITY |
+--------------+--------------+------------+-------------+------------+------------+
| employees | dept_emp | dept_no | 8 | 330400 | 0.0000 |
| employees | salaries | PRIMARY | 286271 | 2760952 | 0.1037 |
| employees | dept_manager | dept_no | 9 | 24 | 0.3750 |
| employees | titles | PRIMARY | 296887 | 440887 | 0.6734 |
| employees | dept_emp | PRIMARY | 298761 | 330400 | 0.9042 |
| employees | titles | PRIMARY | 440166 | 440887 | 0.9984 |
| employees | salaries | PRIMARY | 2760952 | 2760952 | 1.0000 |
| employees | dept_manager | PRIMARY | 24 | 24 | 1.0000 |
| employees | titles | PRIMARY | 440887 | 440887 | 1.0000 |
| employees | departments | PRIMARY | 9 | 9 | 1.0000 |
| employees | employees | PRIMARY | 298124 | 298124 | 1.0000 |
| employees | dept_emp | PRIMARY | 330400 | 330400 | 1.0000 |
| employees | dept_manager | PRIMARY | 24 | 24 | 1.0000 |
| employees | departments | dept_name | 9 | 9 | 1.0000 |
+--------------+--------------+------------+-------------+------------+------------+
--
-- 通過最後一列的SELECTIVITY是否接近1,判斷該索引創建是否合理
-- 注意:
-- Cardinality和table_rows的值,都是通過隨機採樣,預估得到的
-- 當analyze前後,Cardinality值相差較多,說明該索引是不應該被創建的(頁上的記錄數值分佈不平均)
--
-- 推薦 SELECTIVITY 15% 以上是適合的
--
-- 索引使用情況
--
mysql> select * from x$schema_index_statistics limit 1\G
*************************** 1. row ***************************
table_schema: employees
table_name: employees
index_name: PRIMARY -- 索引名字
rows_selected: 300024 -- 讀取的記錄數
select_latency: 370177723990 -- 使用該索引讀取時總的延遲時間370毫秒(單位是皮秒)
rows_inserted: 0 -- 插入的行數
insert_latency: 0
rows_updated: 0 -- 更新的行數
update_latency: 0
rows_deleted: 0
delete_latency: 0
1 row in set (0.00 sec)
-- 結合 之前的SELECTIVITY和這裏的數值,可以更好的判斷索引是否合理
-- 重啓後數據歸0
索引是要排序的,建立索引越多,排序以及維護成本會很大,插入數據的速度會變慢,所以索引建立的多,不是僅僅是浪費空間,還會降低性能,增加磁盤IO
注意:MySQL5.6的版本STATISTICS數據存在問題
,截止5.6.28仍然存在,官方定性爲Bug
作業一:在
MySQL5.6
中使用mysql.innodb_index_stats
得到索引的選擇性(SELECTIVITY)
二. MySQL5.6安裝sys庫
shell > git clone https://github.com/mysql/mysql-sys.git
shell > ls | grep sys_56.sql
sys_56.sql # 這個就是我們要安裝的到mysql5.6的sys
shell> mysql -u root -S /tmp/mysql.sock_56 < sys_56.sql # 直接導入即可
mysql> select version();
+------------+
| version() |
+------------+
| 5.6.27-log |
+------------+
1 row in set (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| burn_test |
| burn_test_56 |
| mysql |
| performance_schema |
| sys | -- 新安裝的sys庫,但是這個裏面只有88個記錄,因爲5.7中增加了幾張表,有101個記錄
| test |
+--------------------+
7 rows in set (0.00 sec)
三. Explain(二)
1. Explain輸出介紹
列 | 含義 |
---|---|
id | 執行計劃的id標誌 |
select_type | SELECT的類型 |
table | 輸出記錄的表 |
partitions | 符合的分區,[PARTITIONS] |
type | JOIN的類型 |
possible_keys | 優化器可能使用到的索引 |
key | 優化器實際選擇的索引 |
key_len | 使用索引的字節長度 |
ref | 進行比較的索引列 |
rows | 優化器預估 的記錄數量 |
filtered | 根據條件過濾得到的記錄的百分比[EXTENDED] |
extra | 額外的顯示選項 |
(1). id
從上往下理解
,不一定 id 序號大的先執行
可以簡單的理解爲 id 相等的從上往下看,id 相等的從下往上看。但是在某些場合也
不一定適用
(2). select_type
select_type | 含義 |
---|---|
SIMPLE | 簡單SELECT(不使用UNION或子查詢等) |
PRIMARY | 最外層的select |
UNION | UNION中的第二個或後面的SELECT語句 |
DEPENDENT UNION | UNION中的第二個或後面的SELECT語句,依賴於外面的查詢 |
UNION RESULT | UNION的結果 |
SUBQUERY | 子查詢中的第一個SELECT |
DEPENDENT SUBQUERY | 子查詢中的第一個SELECT,依賴於外面的查詢 |
DERIVED | 派生表的SELECT(FROM子句的子查詢) |
MATERIALIZED | 物化子查詢 |
UNCACHEABLE SUBQUERY | 不會被緩存的並且對於外部查詢的每行都要重新計算的子查詢 |
UNCACHEABLE UNION | 屬於不能被緩存的 UNION中的第二個或後面的SELECT語句 |
- MATERIALIZED
- 產生中間臨時表(實體)
- 臨時表自動創建索引並和其他表進行關聯,提高性能
- 和子查詢的區別是,優化器將可以進行
MATERIALIZED
的語句自動改寫成join
,並自動創建索引
(3). table
- 通常是用戶操作的用戶表
- <unionM, N> UNION得到的結果表
- 派生表,由id=N的語句產生
- 由子查詢物化產生的表,由id=N的語句產生
####(4). type
按照圖上箭頭的順序來看,成本(cost)是從小到大
####(5). extra
- Using filesort:可以使用複合索引將filesort進行優化。提高性能
- Using index:比如使用覆蓋索引
- Using where: 使用where過濾條件
Extra的信息是可以作爲優化的提示,但是更多的是優化器優化的一種說明