Mysql知識總結(三)

MySQL鎖

   在mysql併發訪問時,如果多個用戶在訪問同一張表時,例如用戶A在執行修改表的操作,而同時用戶B發起對該表查詢操作,此時需要讓用戶B知道用戶A正在施加寫操作,這就意味着用戶B此刻需要等待,如何等待,那就需要用到MVCC(併發訪問控制)機制,而該機制是基於鎖來完成;對於多個用戶同時讀來講是沒有問題的,但是同時寫,勢必會導致系統崩潰;所以鎖並非是可有可無的,而是必須具備的,尤其是在併發訪問的模型下.

   執行操作時施加的鎖模式

       讀鎖:共享鎖、非阻塞阻塞、防止我們在讀取、查詢所的時候,別人去執行寫操作;

       寫鎖:獨佔鎖,排它鎖;彼此間是阻塞

         鎖粒度:

           表鎖:TABLE  LOCK   鎖定了整張表

           行鎖:ROW  LOCK      鎖定了需要的行

           粒度越小,開銷越大,但併發性越好;

           粒度越大,開銷越小,但併發性越差;

   鎖的實現位置:

       mysql鎖:可以手動請求顯示鎖;

       存儲引擎鎖:自動進行的(隱式鎖);

   顯示鎖(表級)

       LOCK TABLES

       UNLOCK TABLES

語法:

LOCK TABLES

   tbl_name [[AS] alias] lock_type
   [, tbl_name [[AS] alias] lock_type] ...
lock_type:鎖類型:
   READ [LOCAL]    

  | [LOW_PRIORITY] WRITE


例子1(施加讀鎖)

mysql> LOCK TABLES classes READ;  //我對此表施加爲讀鎖:
Query OK, 0 rows affected (0.00 sec)

mysql> select * from classes; //此時我發起查詢後沒有問題,開多個終端同時訪問的結果也是可以讀(查詢)
+---------+----------------+----------+
| ClassID | Class          | NumOfStu |
+---------+----------------+----------+
|       1 | Shaolin Pai    |       10 |
|       2 | Emei Pai       |        7 |
|       3 | QingCheng Pai  |       11 |
|       4 | Wudang Pai     |       12 |
|       5 | Riyue Shenjiao |       31 |
|       6 | Lianshan Pai   |       27 |
|       7 | Ming Jiao      |       27 |
|       8 | Xiaoyao Pai    |       15 |
+---------+----------------+----------+
8 rows in set (0.00 sec)

mysql> INSERT INTO classes VALUE (9,'taoyuanji',34); //如果我對其插入數據那麼它將阻塞,我的終端中沒有任何輸出了


mysql> UNLOCK TABLES;  //解鎖
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO classes VALUE (9,'taoyuanji',34); //只要一解鎖這邊就成功寫入(看這條插入語句所經歷的時間)
Query OK, 1 row affected (
1 min 21.91 sec)


例子2(施加寫鎖)


mysql> LOCK TABLES classes WRITE; //我對此表施加爲讀鎖(如果別人也施加了寫鎖,那我這裏會失敗的)
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM classes;
//我在另外一個終端中發起查詢操作,此時我鍵入此語句後它將會阻塞,因爲寫鎖是獨佔的,排他性的,所以其他用戶的讀和寫此時都將會阻塞;


mysql> UNLOCK TABLES; //解鎖
Query OK, 0 rows affected (0.00 sec)


mysql> INSERT INTO classes VALUE (9,'taoyuanji',34);  //當寫鎖被解鎖後立即完成查詢操作(看它的時間)
Query OK, 1 row affected (1 min 21.91 sec)

mysql> SELECT * FROM classes;
+---------+----------------+----------+
| ClassID | Class          | NumOfStu |
+---------+----------------+----------+
|       1 | Shaolin Pai    |       10 |
|       2 | Emei Pai       |        7 |
|       3 | QingCheng Pai  |       11 |
|       4 | Wudang Pai     |       12 |
|       5 | Riyue Shenjiao |       31 |
|       6 | Lianshan Pai   |       27 |
|       7 | Ming Jiao      |       27 |
|       8 | Xiaoyao Pai    |       15 |
|       9 | taoyuanji      |       34 |
+---------+----------------+----------+
9 rows in set (
3 min 20.79 sec)


InnoDB存儲引擎也支持另外一種顯示鎖(鎖定挑選出的部分行,行級鎖);

SELECT ......LOCK IN SHARE MODE;

SELECT ......FOR UPDATE;


事務:Transaction

事務就是一組原子性的查詢語句,將多個查詢當作一個獨立單元.

ACID測試:能滿足ACID測試就表示其支持事務,或兼容事務.

A:Atomicity       原子性

C:Consistency     一致性

I:Isolation       隔離性,一個事務的所有修改操作在提交之前對其他事務是不可見的

D:Durability      持久性,一旦事務得到提交,其所做的修改會永久有效

隔離級別:

READ UNCOMMITTED(讀未提交)  髒讀,不可重讀;能夠看到別人尚未提交的修改

READ COMMITTED(讀提交)   不可重讀,幻讀

REPEATABLE READ(可重讀)   幻讀

SERIALIZABLE(可串行化)   強制事務的串行執行避免了幻讀

事務回滾

mysql>HELP CONTENTS;

mysql>HELP Transcations

mysql>START TRANSACTION  開啓事務

mysql>COMMIT 提交

mysql>ROLLBACK 回滾

設置回滾點

mysql>SAVEPOINT identifier

回滾到指定的位置

mysql>ROLLBACK [WORK] TO [SAVEPOINT] identifier

RELEASE SAVEPOINT identifier


如果沒有顯示啓動事務,每個語句都會當作一個單獨的事務,其執行完成後會被自動提交;


查看自動提交是否啓用

mysql>SHOW GLOBAL VARIABLES LIKE 'autocommit';

or

mysql>SELECT @@ GLOBAL.autocommit;

設置自動提交爲關閉,一旦關閉我們就需要手動就行提交

mysql>SET GLOBAL autocommit  = 0;

查看Mysql的事務隔離級別

mysql>SHOW {GLOBAL|SESSION} VARIABLES LIKE 'tx_isolation';

or

mysql>SELECT @@{GLOBAL|SESSION}.tx_isolation;

設置隔離級別:

mysql>set {GLOBAL|SESSION} tx_isolation '各隔離級別名'

建議:
    對事物要求不特別嚴格的場景下,可以使用讀提交

MVCC :多版本併發控制

      每個事務啓動時,InnoDB會爲每個啓動的事務提供一個當下時刻的快照;

      爲了實現此功能,INNODB會爲每個表提供兩個隱藏的字段,一個用於保存行的創建時間,一個用於保存行的失效時間


Mysql存儲引擎:

MySQL存儲引擎:存儲引擎也通常稱作"表類型"

查看本mysql服務器所支持的存儲引擎:

mysql>SHOW ENGINES;

查看錶的存儲引擎

mysql>SHOW TABLE STATUS [{FROM | IN} db_name]
   [LIKE 'pattern' | WHERE expr]

一張表中的狀態詳細信息

Name:  表名
        Engine:  存儲引擎
       Version:  版本
    Row_format:  行格式

          {DEFAULT|DUNAMIC|FIXED|COMPRESSED|PREDUNDANT|COMPACT}

          Rows:  表中的行數

Avg_row_length:  平均每行包含的字節數
   Data_length:  表數據的總體大小(表中的行數*平均每行包含的字節數)

Max_data_length:  表的最大佔用空間的容量
  Index_length:  索引     的大小
     Data_free:  對於MyISAM表,表示已分配,但尚未使用的空間;包含了以前被刪除的行,這些空間可以用於以後的INSERT語句
Auto_increment:  下一個AUTO_INCREMENT的值
   Create_time:  表的創建時間
   Update_time:  表數據的最近一次的修改時間
    Check_time:  使用CHECK TABLE或myisamchk最近一次檢測表的時間
     Collation:  排序規則
      Checksum:  如果啓用,則爲表的checksum
Create_options:  創建表時指定使用的其他選項
       Comment:  表的註釋



各存儲引擎的特性:

InnoDB:

事務:事務日誌

外鍵:

MVCC:多版本併發控制

聚簇索引:

   聚簇索引(對於INNODB來說)之外的其他索引,通常成爲輔助索引

   輔助索引-->聚簇索引-->數據

       索引類型:B樹索引, R樹索引, hash索引, 全文索引

行級鎖:間隙鎖

支持輔助索引:

支持自適應hash索引

支持熱備份

MyISAM:

全文索引:

支持表壓縮,用於是實現數據倉庫,能節約存儲空間並提升性能

空間索引

表級鎖

延遲更新索引

不支持事務, 外鍵, MVCC, 行級鎖;崩潰後無法安全恢復數據;

適用場景:只讀數據, 較小的表, 多讀少寫

ARCHIVE:

僅支持INSERT和SELECT,支持很好的壓縮功能

適用於存儲日誌信息,或其他按照時間序列實現的數據採集類的應用;

不支持事務,不能很好的支持索引;

CSV:

將數據存儲爲CSV格式,不支持索引;僅適用於數據交換場景;

BLACKHOLE:

沒有存儲機制,任何發往此引擎的數據都會被丟棄;其會記錄二進制日誌,因此,常用於多級複製架構中作中轉服務器;

MEMORY:

保存數據在內存中,內存表;常用於保存中間數據,如週期性的聚合數據等;也用於實現臨時表

支持hash索引,使用表級鎖,不支持BLOB和TEXT數據類型;

MRG_MYISAM:

是MYISAM的一個變種,能夠將多個MyISAM表合併一個虛表;

NDB:

是MySQL CLUSTER中專用的存儲引擎


第三方存儲引擎:

 OLTP類:

XtraDB:增強的InnoDB,由Percona提供;

         編譯安裝mysql時下載XtraDB的源碼替換存儲引擎中的InnoDB的源碼

    PBXT:MariaDB自帶此存儲引擎

         支持引擎級別的複製、外鍵約束、對SSD磁盤提供適當的支持;

         支持事務、MVCC  

    ToKuDB:使用Fractal Trees索引,適用於存儲大數據,擁有很高的壓縮比;已經被引入MariaDB;

 列式存儲引擎:

Infobright:適用於海量數據存儲場景,如PB級別,專爲數據分析和數據倉庫設計;

InfiniDB

MonetDB

LucidDB

 開源社區存儲引擎

Aria:前身Maria,增強版的MyISAM(支持崩潰後安全恢復,支持數據緩存)

Groona:全文索引引擎;完成全站搜索——>改進版,基於Mroonga二次開發

OQGraph:由Open Query研發,支持圖結構的存儲引擎

SphinxSE:爲Sphinx全文搜索服務器提供了SQL接口

Spider:能將數據切分成不同分片,比較高效透明地實現了分片,並支持在分片上支持並行查詢;


更多詳細信息可以參考此表

wKioL1NFKxSwouOPAALmBgbU3Gk251.jpg

如何選擇一個適合於自己的存儲引擎:

1.是否需要事務

2.備份的類型的支持

3.崩潰後的恢復

4.特有的特性

  綜合考慮即可!


Mysql用戶管理:

用戶賬號:'username'@'hostname',password    

用戶賬號管理:

mysql>CREATE USER

mysql>DROP USER

mysql>RENAME USER

mysql>SET PASSWORD

權限管理:

mysql>GRANT

mysql>REVOKE

創建用戶:默認獲取到的授權爲USAGE

mysql>CREATE USER 'username'@'hostname' [IDENTIFIED BY [PASSWORD] 'password' ];

查看用戶能夠使用的權限:

mysql>SHOW GRANTS FOR 'username'@'hostname'

用戶名改名:

mysql>RENAME old_'username'@'hostname' TO new_'username'@'hostname'

設置密碼:

mysql>SET PASSWORD FOR 'username'@'hostname'

Mysql用戶權限管理:

MySQL的權限類別:
   管理類權限:

CREATE TEMPORARY TABLES 創建臨時表
CREATE USER             創建用戶
FILE                    在服務器上讀取或寫入文件
SUPER                   不便歸類的權限,雜項
SHOW DATABASES          列出數據庫
RELOAD                  重置
SHUTDOWN                關閉服務器
REPLICATION SLAVE       複製從服務器的權限,從服務器到主服務器上覆制數據需要SLAVE權限從服務器上的用戶必須具有上面兩個權限才能從主服務器上覆制數據
REPLICATION CLIENT      複製客戶端權限,如果一個用戶需要到服務器上獲取複製主機的相關信息,需要CLIENT權限
LOCK TABLES             顯示施加表鎖
PROCESS                 查看線程列表(msyql>SHOW PROCESSLIST)

   庫級別和表級別:

ALTER                   修改TABLE
ALTER ROUTINE           修改存儲歷程(存儲過程、存儲函數)
CREATE                  創建表和庫
CREATE ROUTINE          創建存儲過程或存儲函數
CREATE VIEW             創建視圖
DROP                    刪除庫或表
EXECUTE                 執行存儲過程或存儲函數
GRNAT OPTION            把自己獲得的權限轉讓
INDEX                   創建和刪除索引
SHOW VIEW               查看一個視圖是如何創建的

    數據操作(表級別):

SELECT   刪除
INSERT   插入
UPDATE   更新
DELETE   刪除

    字段級別:

SELECT(col1,...)
UPDATE(col1,...)
INSERT(col1,...)

所有權限:

ALL [PRIVILEGES]

GRANT命令用法

GRANT ALL ON [FUNCTION] *.*


    GRANT priv_type [(column_list)]
          [, priv_type [(column_list)]] ...
        ON [TABLE|FUNCTION|PROCEDURE] priv_level
        TO username@hostname [IDENTIFIED BY 'password'], [username@hostname [],...]
        [REQUIRE SSL]
        [WITH with_option ...]

priv_level:
   *                        所有對象
 | *.*                      所有庫的所有對象
 | db_name.*                指定庫的所有對象
 | db_name.tbl_name         指定庫的制定表
 | tbl_name                 指定表
 | db_name.routine_name     指定庫的存儲歷程

with_option:
   GRANT OPTION                   把自己獲得的權限轉贈給其他用戶
 | MAX_QUERIES_PER_HOUR count     每小時所執行的最多查詢請求次數
 | MAX_UPDATES_PER_HOUR count     每小時所執行的最多更新次數
 | MAX_CONNECTIONS_PER_HOUR count 每小時所能建立連接的次數
 | MAX_USER_CONNECTIONS count     指定某個用戶帳號最多能同時使用一個帳號連接的次數

收回授權:

REVOKE
   priv_type [(column_list)]
     [, priv_type [(column_list)]] ...
   ON [object_type] priv_level
   FROM user [, user] ...

REVOKE ALL PRIVILEGES, GRANT OPTION
   FROM user [, user] ...

跟用戶授權相關的表:

db:庫級別權限

host:主機級別權限,已廢棄

tables_priv:列級別的權限

procs_priv:存儲過程和存儲函數相關的權限

proxies_priv:代理用戶權限



MySQL查詢緩存:

   MySQL查詢緩存的功能主要是將查詢計劃執行結果緩存下來,當多個用戶執行相同操作時會加快查詢操作;

兩種緩存機制:

   1.查詢語句提交給存儲引擎執行之前,這個查詢計劃一定是做了解析的,如果能將這個查詢計劃緩存下來,當同一個用戶請求相應操作時就不用去解析了;

   2.將查詢後返回的數據給緩存下來,它能夠保存查詢返回的完整結果;被命中時,MySQL會立即返回結果,省去解析、優化和執行等階段。

wKiom1NGkCfS-knQAAB9rN1Qy6k447.jpg

緩存機制大致流程

當一個查詢請求進入服務器檢查是否被命中,如果命中則直接返回;如果否則需要解析語句、優化、執行,執行後的結果最後檢查能否需要緩存,如果需要緩存則就將就結果存入緩存當中;所以這樣一來只要我們開啓了緩存功能它都會去檢查緩存,這樣一來就多了一些開銷、步驟;


如何檢查緩存?

MySQL保存結果於緩存中:
    把SELECT語句本身做hash計算,計算的結果作爲key,查詢結果作爲value

什麼樣的語句不會被緩存?
查詢語句中有一些不確定數據時,不會緩存:例如NOW(), CURRENT_TIME();一般來說,如果查詢中包含用戶自定義函數、存儲函數、用戶變量、臨時表、mysql庫中系統表、或者任何包含權限的表,一般都不會緩存;

緩存會帶來額外開銷:
1、每個查詢都得先檢查是否命中;
2、查詢結果要先緩存;

查詢緩存完全是在內存中實現的,而內存空間是有限的,能夠分配給查詢緩存使用的空間也是有限的,如果空間佔滿了,那麼會通過緩存策略將那些老的緩存給清除,但是這個過程又會增加開銷,反覆存入、釋放、存入、釋放,內存中就會產生許多碎片,就會變得很麻煩,於是選擇一個合適的緩存策略是一個值得思考問題.

在mysql服務器上設定緩存策略:

查看當前mysql服務器的緩存變量

mysql> SHOW GLOBAL VARIABLES LIKE 'query_cache%';
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 16777216 |
| query_cache_type             | ON       |
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+

query_cache_type: 查詢緩存類型;是否開啓緩存功能,開啓方式有三種{ON|OFF|DEMAND};
DEMAND:按需緩存;意味着SELECT語句明確使用 SQL_CACHE 選項時纔會緩存;

query_cache_size: 總空間,單位爲字節,大小必須是1024的整數倍。MySQL啓動時,會一次分配並立即初始化這裏指定大小的內存空間;這意味着,如果修改此大小,會清空緩存並重新初始化的.

query_cache_min_res_unit: 存儲緩存的最小內存塊;(query_cache_size-Qcache_free_memory)/Qcache_queries_in_cache能夠獲得一個理想的值.

query_cache_limit: 單個緩存對象的最大值,超出時則不預緩存;手動使用SQL_NO_CACHE可以人爲地避免嘗試緩存返回結果超出此參數限定值的語句.

query_cache_wlock_invalidate: 如果某個表被其它用戶連接鎖住了,是否仍然從緩存中返回結果。OFF表示返回.

如何判斷命令率:

查看當前mysql服務器的緩存狀態變量(不可設定,只需觀測)

mysql> SHOW GLOBAL STATUS LIKE 'Qcache%';
+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 16751304 |
| Qcache_hits             | 1        |
| Qcache_inserts          | 8        |
| Qcache_lowmem_prunes    | 0        |
| Qcache_not_cached       | 33       |
| Qcache_queries_in_cache | 5        |
| Qcache_total_blocks     | 14       |
+-------------------------+----------+

Qcache_free_blocks     空閒的塊數
Qcache_free_memory     尚且空閒緩存空間大小
Qcache_hits:          緩存命中次數            

Qcache_inserts:       向緩存空間中緩存數據的次數        

Qcache_lowmem_prunes   因內存太少,修減內存的次數
Qcache_not_cached      沒有緩存的
Qcache_queries_in_cache在緩存中緩存的查詢的個數
Qcache_total_blocks    總塊數

緩存空間只有被初始化、分配以後用來緩存數據的;

空閒空間表示尚未劃分用來存數據格式的空間

總空間 - 剩餘空間 = 已用空間

並非已用空間都存了緩存,裏面有的表示已劃分好格式了,隨時等待緩存,但尚未進行緩存

如果內存中確實有碎片了,而內存還有足夠的空間;這是我們需要進行碎片整理

碎片整理:FLUSH QUERY_CACHE

清空緩存:RESET QUERY_CACHE

計算命中率:

1.通過以下語句獲取查詢次數和命中次數這兩個值

mysql> SHOW GLOBAL STATUS WHERE Variable_name='Qcache_hits' OR Variable_name='Com_select';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select    | 57    |
| Qcache_hits   | 8     |
+---------------+-------+

2.通過下面這個公式計算

Qcache_hits/(Com_select +Qcache_hits)


也應該參考另外一個指標:命中和寫入的比率,即Qcache_hits/Qcache_inserts的值,此比值如果能大於3:1,則表明緩存也是有效的。能達到10:1,爲比較理想的情況。

緩存優化使用思路:
1、批量寫入而非多次單個寫入;
2、緩存空間不宜過大,因爲大量緩存同時失效時會導致服務器假死;
3、必要時,使用SQL_CACHE和SQL_N0_CACHE手動控制緩存;
4、對寫密集型的應用場景來說,禁用緩存反而能提高性能;


MySQL日誌:

查詢日誌:用來保存當前系統上所有跟查詢相關信息的(不僅僅只包含SELECT)


慢查詢日誌:查詢執行時長超過指定時長的查詢;未必是執行語句自身原因,可能是應爲被依賴的資源不被許可訪問.定位系統上查詢操作、執行過慢時的一個評估工具,所以有必要啓用之.


錯誤日誌:MySQL啓動時,複製


二進制日誌:記錄了mysql數據庫中引起數據庫改變的所有操作或有潛在跟修改相關的操作,如果要從頭記錄的話拿到其他服務器上還原後與原服務器基本相同;mysql的複製功能依賴於此日誌複製功能.


中繼日誌:slave server從master server的二進制文件中複製事件過來,並保存至本地的日誌文件中,此日誌文件就叫做中繼日誌      


事務日誌:暫存事務提交的數據

         將隨機I/O轉換爲順序I/O,保證事務的ACID

         日誌文件組:至少應該有兩個/保證事務回滾、提交、一致性    


查詢日誌:(默認是關閉的)

         log={ON|OFF}:是否記錄所有語句的日誌信息於一般查詢日誌文件中(general_log)

         log_output={TABLE|FILE|NONE}   TABLE|FILE 可以同時出現,用逗號分隔

         general_log={ON|OFF}

         general_log_file:定義一般查詢日誌保存位置

             SET GLOBAL log='ON'

             SET GLOBAL general_log='ON' --->數據目錄下:hostname.log

             都需要啓用

             如果記錄到TABLE中  SET GLOBAL log_output='TABLE'

                 會記錄到數據庫的mysql數據庫general_log表中

慢查詢日誌:

    慢查詢時長:超過此時間,就判定爲慢查詢;

    mysql> show global variables like 'long%';

+-----------------+-----------+

| Variable_name   | Value     |

+-----------------+-----------+

| long_query_time | 10.000000 |

+-----------------+-----------+

1 row in set (0.01 sec)


    設定是否啓用慢查詢日誌:

    是否啓用慢查詢日誌,它的輸出位置也取決於log_output={TABLE|FILE|NONE}

    slow_query_log={ON|OFF}

    定義日誌文件路徑及名稱:

    slow_query_log_flile=www-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


#是否啓用記錄慢查日誌

    log_slow_queries=ON


    #定義慢查速

    log_slow_rate_limit=1    


    #是否記錄詳細格式的日誌信

    log_slow_verbosity


錯誤日誌:
    服務器啓動和關閉過程中的信息;
    服務器運行過程中的錯誤信息;
    時間調度器運行一個事件時產生的信息;
    在複製架構中的從服務器上啓動從服務器線程時產生的信息;

  相關參數:

    log_error   /data/mydata/www.stu41.com.err   -->錯誤日誌路徑及名稱

log_warnings  1   -->默認記錄了mysql服務器的警告信息


二進制日誌:
    時間點恢復
    實現mysql的複製



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