mysql高階應用-索引、併發控制、事務、日誌

一、索引

1.使用索引優缺點:
優點:

  • 索引可以降低服務需要掃描的數據量,減少了IO次數
  • 索引可以幫助服務器避免排序和使用臨時表
  • 索引可以幫助將隨機I/O轉爲順序I/O

缺點:

  • 索引佔用額外空間,影響插入速度;一旦數據更新(如插入,刪除),需要維護索引(數據重新排序);

建議:查詢頻率高的建立索引,變更數據多的要考慮是否需要建立索引

2.索引原理:
將物理上存放的不規則的,無順序的數據,通過索引在邏輯上有規則有順序的連接在一起,提高查詢效率。

  • 數值順序:
  • 字符順序:與對應的字符集的字符序相關,如按字母順序:ab與aa,第一個字符相同的情況下,對第二個字符排序,以此類推

3.查詢方式:

  • 連續查詢:如查年齡10~20歲的學生信息
  • 單獨查詢: 如查年齡爲20歲的學生信息

4.分類:

  • B+TREE:
  • HASH:
  • R TREE:
  • 聚簇(集)索引:數據和索引存儲在一起
  • 非聚簇索引:數據和索引分開存放
  • 簡單索引(單列索引):僅一個字段充當索引
  • 複合索引:兩個以上字段作爲索引(需要指定索引字段順序);第一個索引固定的情況下,- 第二個索引纔是按順序排序的,跳過第一個字段直接查詢第二個字段,無法利用索引
  • 主鍵索引:
    主鍵和唯一鍵的區別:
    主鍵只能有一個,唯一鍵可以有多個;
    主鍵值不能爲空,唯一鍵可以爲空;
  • 唯一鍵索引:保證字段值都是唯一的,如手機號
  • 二級(輔助)索引
  • 稠密索引、稀疏索引:是否索引了每一個數據項
  • 簡單索引、組合索引
  • 左前綴索引:取前面的字符做索引
  • 覆蓋索引:從索引中即可取出要查詢的數據,性能高

5.B-Tree 與 B+Tree

(1)B-Tree特性
磁盤塊中存放的數據塊(每個數據塊包含的記錄信息字段數越少)數越多,查詢越快(樹深越淺)

(2)B+Tree特性
(1)每個數據塊存放的是索引字段的值,不存放具體記錄的完整數據,記錄完整信息放在葉子節點
(2)查詢速度都一樣,都要查詢到葉子節點;
(3)鏈表:指定下一個數據塊位置

6.建立B+tree索引條件:
(1)在查詢的where查詢條件建立索引;
(2)查詢記錄數重複比較少的情況,如性別建立索引無意義,可在電話號碼上建立索引
(3)讀多寫少情況

7.B-Tree與B+Tree的區別(優缺點)
B-Tree 缺點
對應範圍查找無能爲力,範圍內每個數都要從根找起

8.管理索引

  • 創建索引
	CREATE INDEX [UNIQUE] index_name ON tbl_name (index_col_name[(length)],...);
ALTER TABLE tbl_name ADD INDEX index_name(index_col_name);
help CREATE INDEX;
  • 查看索引
SHOW INDEXES FROM [db_name.]tbl_name;
  • 刪除索引
DROP INDEX index_name ON tbl_name;
ALTER TABLE tbl_name DROP INDEX index_name(index_col_name);
  • 查看索引的使用
SET GLOBAL userstat=1;
SHOW INDEX_STATISTICS;
  • 優化表空間:
OPTIMIZE TABLE tb_name;

9.分析索引有效性
explain:獲取查詢執行計劃信息,用來查看查詢優化器如何執行查詢
EXPLAIN Output Format 輸出格式參見:
https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

添加索引與未添加索引時間效率對比

二、併發控制:鎖

鎖類型:

  • 讀鎖:共享鎖,只讀不可寫(包括當前事務) ,多個讀互不阻塞
  • 寫鎖:獨佔鎖,排它鎖,寫鎖會阻塞其它事務(不包括當前事務)的讀和寫

鎖粒度:

  • 表級鎖
  • 行級鎖

鎖調用方式:

  • 隱式鎖:由存儲引擎自動施加鎖
  • 顯式鎖:用戶手動請求

顯示調用鎖

LOCK TABLES	#加鎖
    tbl_name [[AS] alias] lock_type
    [, tbl_name [[AS] alias] lock_type] ...

lock_type:
    READ [LOCAL]
  | [LOW_PRIORITY] WRITE

UNLOCK TABLES  #解鎖

關閉正在打開的表(清除查詢緩存),通常在備份前加全局讀鎖

FLUSH TABLES [tb_name[,...]] [WITH READ LOCK]

查詢時加寫或讀鎖

SELECT clause [FOR UPDATE | LOCK IN SHARE MODE]

三、事務

ACID特性:

  • A:atomicity原子性;整個事務中的所有操作要麼全部成功執行,要麼全部失敗後回滾
  • C:consistency一致性;數據庫總是從一個一致性狀態轉換爲另一個一致性狀態
    如銀行轉賬,A賬戶轉賬給B賬戶,A減去10000,B加10000;A不減,B不加,不會出現轉來轉去把錢轉丟
  • I:Isolation隔離性;一個事務所做出的操作在提交之前,是不能爲其它事務所見;隔離有多種隔離級別,實現併發
    如以下場景:原來工資10000,現正在執行加1000事務,這個事務沒有結束,可能會撤銷;另一個事務查看工資記錄;不同隔離級別查看的結果不一樣。
  • D:durability持久性;一旦事務提交,其所做的修改會永久保存於數據庫中
    類比開會後的決議案

作用域:
對DML語句作用:
對DDL語句沒有作用:

啓動事務:

  • BEGIN
  • BEGIN WORK
  • START TRANSACTION

結束事務:

  • COMMIT:提交
  • ROLLBACK: 回滾

事務隔離級別:
從上到下越來越嚴格:

  • read uncommitted:A事務commit前,B事務可查看A正在修改的數據
  • read committed:A事務commit的某個時間段在更新某個數據,在B事務裏不同時間讀到的數據不一樣,可能A事務commit後的結果和B事務查看的結果不一致,導致不可連續讀。
  • repeatable read:(mysql默認設置)A事務commit前某個時間段在更新某個數據,B事務看的數據不變,可連續讀;但A事務commit更新後的數據,B事務看到的數據仍然是未變更前的數據,產生幻讀。配合備份數據庫,備份數據期間,備份的數據時穩定不變的。
  • serializabile:可串行化,未提交的讀事務阻塞修改事務,或者未提交的修改事務阻塞讀事務。導致併發性能差

在這裏插入圖片描述

事務死鎖

四、日誌

日誌分類:

  • 事務日誌 transaction log
  • 錯誤日誌 error log
  • 通用日誌 general log
  • 慢查詢日誌 slow query log
  • 二進制日誌 binary log
  • 中繼日誌 reley log

(一)事務日誌:

#有#註釋的是5.5.60-MariaDB的變量
MariaDB [hellodb]> show variables like '%innodb_log%';
+-------------------------------+------------+
| Variable_name                 | Value      |
+-------------------------------+------------+
| innodb_log_arch_dir           |            |
| innodb_log_arch_expire_sec    | 0          | 
| innodb_log_archive            | OFF        |
| innodb_log_block_size         | 0          |  #日誌塊大小
| innodb_log_buffer_size        | 16777216   |	#日誌緩衝區大小
| innodb_log_checksum_algorithm | DEPRECATED |
| innodb_log_checksums          | ON         |
| innodb_log_compressed_pages   | ON         |
| innodb_log_file_size          | 50331648   |	#日誌文件大小
| innodb_log_files_in_group     | 2          |	#事務文件路徑
| innodb_log_group_home_dir     | ./         |	#事務文件路徑
| innodb_log_optimize_ddl       | ON         |
| innodb_log_write_ahead_size   | 8192       |
+-------------------------------+------------+

事務日誌文件:

#5.5.60-MariaDB 默認單個事務日誌文件大小5M
#10.2.25-MariaDB-log默認48M
#建議事務日誌大小設置大一些數量多一些,防止因事務日誌太小,大事務來回覆蓋日誌文件無法執行下去
[root@CentOS7 ~]#ll /var/lib/mysql/
-rw-rw---- 1 mysql mysql  48M Jul 11 10:24 ib_logfile0
-rw-rw---- 1 mysql mysql  48M Jul 10 19:27 ib_logfile1

innodb_flush_log_at_trx_commit=1
1 默認情況下,日誌緩衝區將寫入日誌文件,並在每次事務後執行刷新到磁盤。 這是完全遵守ACID特性
0 提交時沒有任何操作; 而是每秒執行一次日誌緩衝區寫入和刷新。 這樣可以提供更好的性能,但服務器崩潰可能丟失最後一秒的事務
2 每次提交後都會寫入日誌緩衝區,但每秒都會進行一次刷新。 性能比0略好一些,但操作系統或停電可能導致最後一秒的交易丟失
3 模擬MariaDB 5.5組提交(每組提交3個同步),此項MariaDB 10.0支持

建議將事務日誌存放到單獨磁盤,至少是單獨分區

[root@CentOS7 ~]#vim /etc/my.cnf
innodb_log_group_home_dir=/data/mariadb
[root@CentOS7 ~]#ll -d /data/mariadb/
[root@CentOS7 ~]#chown mysql:mysql /data/mariadb/
[root@CentOS7 ~]#ll -d /data/mariadb/
[root@CentOS7 ~]#systemctl restart mariadb
[root@CentOS7 ~]#ll -h /data/mariadb/

在這裏插入圖片描述

(二)錯誤日誌

記錄內容
1.mysqld啓動和關閉過程中輸出的事件信息
2.mysqld運行中產生的錯誤信息
3.event scheduler運行一個event時產生的日誌信息
4.在主從複製架構中的從服務器上啓動從服務器線程時產生的信息

#5.5.60-MariaDB 默認錯誤日誌路徑/var/log/mariadb/mariadb.log
#10.2.25-MariaDB-lo  默認未指定錯誤日誌路徑
MariaDB [hellodb]>show global variables like 'log_error';

設置錯誤日誌路徑:

[root@CentOS7 ~]#vim /etc/my.cnf
log-error=/data/mariadb/mariadb.log

(三)通用日誌

記錄數據庫的操作,如各種SQL語句;對性能有影響,一般用於排錯時啓用

#默認通用日誌是關閉的,並且mariadb安裝目錄中沒有CentOS7.log文件,只有開啓通用日誌重啓服務後才生成
#general_log=ON|OFF
#general_log_file=HOSTNAME.log
#log_output=TABLE|FILE|NONE  通用日誌輸出方式,table是放到mysql.general_log表中
MariaDB [hellodb]> show variables like 'general%';
+------------------+-------------+
| Variable_name    | Value       |
+------------------+-------------+
| general_log      | OFF         |
| general_log_file | CentOS7.log |
+------------------+-------------+

MariaDB [hellodb]> show variables like 'log_output';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_output    | FILE  |
+---------------+-------+

通用日誌放到文件方式:/var/lib/mysql/CentOS7.log
在這裏插入圖片描述
通用日誌放到數據庫方式:mysql.general_log
在這裏插入圖片描述

(四)慢查詢日誌

#默認慢查詢日誌記錄查詢時間:10s
MariaDB [mysql]> show variables like 'long%';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
#默認慢查詢日誌啓用狀態:未啓用
#mariadb安裝目錄中沒有CentOS7-slow.log文件,只有開啓通用日誌重啓服務後才生成
MariaDB [mysql]> show variables like 'slow_query_log';
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| slow_query_log | OFF   |
+----------------+-------+
MariaDB [hellodb]> show variables like 'log_queries_not_using_indexes';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | OFF   |
+-------------------------------+-------+

#是否啓用查詢執行過程詳細信息
MariaDB [hellodb]> show variables like 'profiling';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| profiling     | OFF   |
+---------------+-------+

慢查詢日誌常用變量

slow_query_log=ON|OFF 	 #開啓或關閉慢查詢
long_query_time=N 	#慢查詢的閥值,單位秒
slow_query_log_file=HOSTNAME-slow.log 	#慢查詢日誌文件路徑,主機名-slow.log
log_slow_filter = admin|filesort|filesort_on_disk|full_join|full_scan|query_cache|query_cache_miss|tmp_table|tmp_table_on_disk
#上述查詢類型且查詢時長超過long_query_time,則記錄日誌
log_queries_not_using_indexes=ON #不使用索引的查詢語句或使用全索引掃描的語句,不論是否達到慢查詢閥值的語句是否記錄日誌,默認OFF,即不記錄
log_slow_rate_limit = 1 #多少次查詢才記錄,mariadb特有
log_slow_verbosity= Query_plan,explain 	#記錄內容

啓用慢查詢日誌配置:

[root@CentOS7 data]#vim /etc/my.cnf
slow_query_log
long_query_time=3 #設置超過3秒記錄慢查詢日誌
profiling

慢查詢語句

MariaDB [hellodb]> select sleep(1) from students;

在這裏插入圖片描述
查看某條慢查詢語句具體執行時間

MariaDB [hellodb]> set profiling=on;
MariaDB [hellodb]> select sleep(1) from students;
MariaDB [hellodb]> show profiles;
+----------+------------+---------------------------------+
| Query_ID | Duration   | Query                           |
+----------+------------+---------------------------------+
|        1 | 0.00035217 | show variables like 'profiling' |
|        2 | 4.00351785 | select sleep(1) from teachers   |
|        3 | 0.00005712 | show profiles for query 2       |
+----------+------------+---------------------------------+
3 rows in set (0.00 sec)

MariaDB [hellodb]> show profile for query 2;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000127 |開始
| checking permissions | 0.000007 |檢查權限
| Opening tables       | 0.000012 |打開表
| After opening tables | 0.000006 |打開表後
| System lock          | 0.000004 |系統鎖
| Table lock           | 0.000002 |鎖表
| After table lock     | 0.000004 |鎖表後
| init                 | 0.000016 |初始化
| optimizing           | 0.000007 |優化
| statistics           | 0.000014 |統計
| preparing            | 0.000008 |準備
| executing            | 0.000003 |執行
| Sending data         | 0.000078 |發送數據
| User sleep           | 1.000871 |
| User sleep           | 1.000847 |
| User sleep           | 1.001120 |
| User sleep           | 1.000285 |
| end                  | 0.000014 |結束
| query end            | 0.000023 |查詢結束
| closing tables       | 0.000008 |關閉表
| freeing items        | 0.000006 |釋放項目
| updating status      | 0.000013 |更新狀態
| logging slow query   | 0.000041 |記錄慢查詢
| cleaning up          | 0.000002 |清理
+----------------------+----------+

注:
1.執行的事務中,如果有插入數據的操作,在事務結束前,除了事務日誌文件大小在變大,同時數據文件大小也會隨事務中插入數據量變大;但是如果事務以rollback回滾方式結束事務,則數據文件顯示大小並沒有變化;
2.如果此時不通過事務再插入數據,在爲達到之前事務插入的數據量前,數據文件大小顯示一直沒有變化,直到插入數據量大於之前事務準備插入的數據量,數據文件大小纔不斷增加!
3.即使把表情況,數據文件大小仍然不會縮減

[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #10K
[root@CentOS7 ~]#msyql -uroot -p
MariaDB [hellodb]> begin;
MariaDB [hellodb]> call sp_testlog;   #創建testlog表並插入10萬條數據的存儲過程
MariaDB [hellodb]> rollback;
[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #12M
MariaDB [hellodb]> call sp_testlog;
[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #12M
MariaDB [hellodb]> call sp_testlog;
[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #24M 
MariaDB [hellodb]> delete from testlog;
[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #24M
MariaDB [hellodb]> optimize tables testlog; #優化數據庫
[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #0M

(五)客戶端日誌

#用戶家目錄.mysql_history存放客戶端執行的SQL語句
[root@CentOS7 ~]#cd
[root@CentOS7 ~]#ll -a
[root@CentOS7 ~]#cat .mysql_history

在這裏插入圖片描述

(六)二進制日誌

記錄SQL語句,記錄對數據庫的增刪改,不記錄查操作;日誌不像事務日誌有覆蓋現象,日誌一直累積。
強烈建議: 二進制日誌單獨存放磁盤,至少單獨分區

#兩個變量都啓用才行
MariaDB [hellodb]> show variables like 'sql_log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sql_log_bin   | ON    |
+---------------+-------+
1 row in set (0.00 sec)

MariaDB [hellodb]> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | OFF   |
+---------------+-------+
1 row in set (0.00 sec)

#log_bin必須寫配置文件開啓
#sql_log_bin用於臨時開啓、關閉二進制日誌;會話級變量,只能在一個ssh的shell窗口臨時關閉
MariaDB [hellodb]> set log_bin=on;
ERROR 1238 (HY000): Variable 'log_bin' is a read only variable

二進制日誌相關變量

sql_log_bin=ON|OFF	#否記錄二進制日誌,默認ON
log_bin=/PATH/BIN_LOG_FILE	#指定文件位置;默認OFF,表示不啓用二進制日誌功能,上述兩項都開啓纔可
binlog_format=STATEMENT|ROW|MIXED #二進制日誌記錄的格式,默認STATEMENT,建議最好改爲ROW,其次使用Mixed
max_binlog_size=1073741824	#單個二進制日誌文件的最大體積,到達最大值會自動滾動,默認爲1G
#說明:文件達到上限時的大小未必爲指定的精確值
sync_binlog=1|0	#設定是否啓動二進制日誌即時同步磁盤功能,默認0,由操作系統負責同步日誌到磁盤考慮性能選擇0,考慮數據安全性選1
expire_logs_days=N	#二進制日誌可以自動刪除的天數。 默認爲0,即不自動刪除

設置開啓二進制日誌配置:

[root@CentOS7 ~]#mkdir /data/logbin
[root@CentOS7 ~]#chown mysql.mysql /data/logbin/
[root@CentOS7 ~]#vim /etc/my.cnf
log_bin=/data/logbin/mysql-bin   #log_bin=文件名路徑+前綴,不寫按默認路徑和文件名前綴生成
binlog_format=row     #二進制日誌記錄形式
[root@CentOS7 data]#systemctl restart mariadb
[root@CentOS7 data]#ll /var/lib/mysql/
	CentOS7-bin.000001	#10.2.25-MariaDB-lo 默認二進制文件名
[root@CentOS7 data]#ll /var/lib/mysql/
	mariadb-bin.000001	#5.5.60-MariaDB 默認二進制文件名

在這裏插入圖片描述
如何查看二進制文件?
(1)數據庫自帶命令方式查看:

#查看所有二進制日誌文件
MariaDB [hellodb]> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |  29078035 |
+------------------+-----------+
1 row in set (0.00 sec)

MariaDB [hellodb]> show master logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |  29078035 |
+------------------+-----------+
1 row in set (0.00 sec)

#查看當前正在使用的二進制日誌文件
#Position 通過大小標記日誌位置,用於數據庫還原判定起始位置
MariaDB [hellodb]> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 | 29078035 |              |                  |
+------------------+----------+--------------+------------------+

#以文件形式查看二進制文件
MariaDB [hellodb]> show binlog events in 'CentOS7-bin.000001';
#查看某個位置之後的
MariaDB [hellodb]> show master status;
MariaDB [hellodb]> insert students (name,age) values('xiaomi',30);
MariaDB [hellodb]> show master status;
MariaDB [hellodb]> show binlog events in 'CentOS7-bin.000001' from 54756314;
+--------------------+----------+------------+-----------+-------------+---------------------------------------------------------------+
| Log_name           | Pos      | Event_type | Server_id | End_log_pos | Info                                                          |
+--------------------+----------+------------+-----------+-------------+---------------------------------------------------------------+
| CentOS7-bin.000001 | 54756314 | Gtid       |         1 |    54756356 | BEGIN GTID 0-1-200003                                         |
| CentOS7-bin.000001 | 54756356 | Intvar     |         1 |    54756388 | INSERT_ID=27                                                  |
| CentOS7-bin.000001 | 54756388 | Query      |         1 |    54756504 | use `hellodb`; insert students (name,age) values('xiaomi',30) |
| CentOS7-bin.000001 | 54756504 | Xid        |         1 |    54756535 | COMMIT /* xid=600027 */                                       |
+--------------------+----------+------------+-----------+-------------+---------------------------------------------------------------+

在這裏插入圖片描述

(2)客戶端工具查看二進制日誌:mysqlbinlog

使用語法

mysqlbinlog [OPTIONS] log_file…
--start-position=# 指定開始位置
--stop-position=#
--start-datetime=
--stop-datetime=
時間格式:YYYY-MM-DD hh:mm:ss
--base64-output[=name]
-v -vvv
[root@CentOS7 data]# mysqlbinlog --start-position=54756314 /var/lib/mysql/CentOS7-bin.000001
[root@CentOS7 data]# mysqlbinlog --start-position=54756314 /var/lib/mysql/CentOS7-bin.000001 -v #-v在最後能看到SQL語句

加v與不加v的區別:
不加v:
在這裏插入圖片描述
加v:
在這裏插入圖片描述
清除指定二進制日誌:
PURGE { BINARY | MASTER } LOGS
{ TO ‘log_name’ | BEFORE datetime_expr }
示例:
PURGE BINARY LOGS TO ‘mariadb-bin.000003’;刪除3之前的日誌
PURGE BINARY LOGS BEFORE ‘2019-01-23’;
PURGE BINARY LOGS BEFORE ‘2019-03-22 09:25:30’;
刪除所有二進制日誌,index文件重新記數

RESET MASTER [TO #]; 刪除所有二進制日誌文件,並重新生成日誌文件,文件名從#開始記數,默認從1開始,一般是master主機第一次啓動時執行,MariaDB10.1.6開始支持TO #
切換日誌文件:
FLUSH LOGS;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章