日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql优化 个人笔记 (mysql锁机制 ) 非礼勿扰 -m10

發布時間:2024/3/13 数据库 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql优化 个人笔记 (mysql锁机制 ) 非礼勿扰 -m10 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

鎖機制

A : undolog 實現
C :
I :鎖實現
D :redolog實現

1. mysql鎖基本介紹

鎖是計算機協調多個進程或線程并發訪問某一資源的機制
在數據庫中 除了傳統的計算機資源(CPU RAM I/O等)的的爭用外,
數據也是一種共享資源,如何保證數據訪問的一致性,有效性?
是所有數據庫必須要解決的問題。
鎖沖突也是影響數據庫訪問的一個重要因素。
從這個角度看,鎖機制很重要。

相對其他數據庫而言,mysql的鎖機制比較簡單,不同的存儲引擎支持不同的鎖機制,
MyISAM 和 memory 存儲引擎采用的表級鎖(table-level locking)
Innodb 存儲引擎支持行級別鎖(row-level locking)也支持表級鎖哦
表級鎖:
1. 開銷小,加鎖快,不會死鎖,
2. 鎖粒度大,發生沖突概率高,并發度低
行級鎖:
1. 開銷大 加鎖慢 鎖定力度小 發生沖突概率低 并發高
2. 會出現死鎖
從上述特點可見,很難籠統的說那種鎖更好,只能具體場景具體分析
從鎖的角度來說:
1 . 表級鎖更適合查詢 ,只有少量按索引條件更新數據的應用 web應用
2 . 行級鎖,適合有大量按索引條件并發更新不同數據,同時又有并發查詢的應用
OLTP系統
OLTP : Online Transaction Processing 在線事物處理 (增刪改的多)
OLAP:Online Analytical Processing 在線分析處理 歷史數據的分析( 查詢 )


2.MyISAM

串行:
mysql 的表級鎖有兩種模式: 表共享讀鎖(Table Read Lock) 和 表獨占寫鎖(Table Write Lock)

  • 對于MyISAM表的讀操作,不會阻塞其他用戶對同一表的請求,但會阻塞對同一表的請求
  • 對于MyISAM表的寫操作,會同時阻止其他用戶對同一個表的讀和寫
  • 讀 寫 串 行 !
  • -- 創建表 CREATE TABLE `test` (`id` bigint NOT NULL ,`name` varchar(255) NULL ,PRIMARY KEY (`id`) ) engine =MyISAM DEFAULT CHARSET=UTF8;CREATE TABLE `person` (`id` bigint NOT NULL ,`age` int NULL ,PRIMARY KEY (`id`) ) engine =MyISAM DEFAULT CHARSET=UTF8; -- 造數據 INSERT INTO `test`.`test` (`id`, `name`) VALUES ('1', 'a'); INSERT INTO `test`.`test` (`id`, `name`) VALUES ('2', 'b'); INSERT INTO `test`.`test` (`id`, `name`) VALUES ('3', 'c'); INSERT INTO `test`.`test` (`id`, `name`) VALUES ('4', 'd');

    Mysql安裝目錄下 嘍一眼 是MyISAN存儲引擎的格式

    1. 打開2個客戶端窗口 (我用的開倆navicate ) 2. 演示一個 寫鎖阻塞讀的案例 當一個線程獲取一個表的寫鎖之后,只有持有這個鎖的線程可以對表進行更新操作,其他線程的操作會等待 直到獲取鎖的線程釋放鎖以下稱Navicat第一個窗口為N1 Navicat第二個窗口為N2 1. N1: lock table test write;2. N2:select * from test; -- 卡住了 等鎖呢 3. N1:select * from test; -- 能查詢4.N1:insert into test values(5,'e'); -- 能插入數據update test set name = 'ee' where id = 5; -- 能更新數據 5.N2 還卡著呢(可能會超時)6. N1:unlock tables; 7. N2:不卡了 有執行結果了(結果里有ee了)

    -- 讀阻塞寫的案例 還是N1 和 N2 1. N1 : lock table test read; 2. N1:select * from test; -- 有數據 3. N2:select * from test; -- 有數據 4. N1:select * from person ; -- N1不能查詢其他表 5. N2:select * from person ; -- N2 可以查詢其他表 6. N1:insert into test values(5,'e'); --N1不能插入 報錯 -- Table 'test' was locked with a READ lock and can't be updated 7. N2:insert into test values(6,'f'); -- N2插入不報錯,但是會卡住 阻塞 8. N1:update test set name = 'qqq' where id = 5; -- N1 更新也會報錯 -- 1099 - Table 'test' was locked with a READ lock and can't be updated 9. N1: unlock tables; -- 釋放鎖 10.N2 : 剛才的更新成功 總結: 也就是N1獲取一個表的鎖之后 不能操作其他表 不能對本表新增(報錯)+修改(報錯)N1獲取一個表的鎖后,N2可以操作其他表,不能對N1獲取鎖的表進行修改(等待)

    注意

    MyISAM 在執行查詢語句之前,會自動給涉及的表加讀鎖,在執行更新操作前,會自動給涉及的表加寫鎖,這個過程不需要用戶干預,因此用戶一般不需要使用命令來顯示的加鎖,一般只有自己在測試這個過程加鎖過程的時候,才會手動加鎖,來模擬各種場景


    并行:
    MyISAM 表的讀和寫是串行的,這是就總體而言的,
    在一定條件下MyISAM也支持查詢和插入操作的并發執行!
    MyISAM存儲引擎有一個系統變量concurrent_insert 專門用來控制并發行為,
    值分別是 0(NEVER) 1(AUTO) 2(ALWAYS )

    • 當值為0(NEVER) 時 不允許并發插入
    • 當值為1(AUTO)時,如果表中沒有被刪除的行(空洞),允許一個進程讀的同時,另一個進程寫操作
    • 當值為2(ALWAYS) 無論表中有沒有空洞,都允許表尾并發插入記錄

    實驗:

    show VARIABLES like '%concurrent_insert%' -- 顯示AUTO 也就是1 -- 還用上邊的N1 N2 N1:lock table test read local; N1:SELECT * FROM test; -- 可以查詢結果 N1:INSERT INTO TEST VALUES(7,'G'); -- 失敗 Table 'TEST' was locked with a READ lock and can't be updated N2:INSERT INTO TEST VALUES(7,'G'); -- 成功 N1:SELECT * FROM test; -- 可以查詢結果 但沒有 7,G 這條記錄 N2:SELECT * FROM test; -- 可以查詢結果 有新增的7,G 這條記錄 N2:UPDATE TEST SET NAME='CC' WHERE ID=3; -- 阻塞 N1:UNLOCK tables; --解鎖 N2:上一步update成功 N1:SELECT * FROM test; -- N2的新增 和 update 的行 都可以看到 --說明 在N1 lock read locl 的時候 N1 可以查詢 插入 但是不能更新 刪除

    可以通過檢查table_locks_waited 和 table_locks_immidiate 的狀態變量來分析系統上的表鎖爭奪:

    show status like '%table_locks%'


    – 如果table_locks_waited 的值比較大,則說明存在嚴重的表鎖爭用情況


    3.InnoDB

    1、事物及其ACID屬性
    事物是由一組SQL語句組成的邏輯處理單元,事物具有4個屬性,通常稱之為ACID

    • 原子性(Actomicity):事物的原子性,對數據的修改,要么全成功 ,要么全失敗 (undolog)
    • 一致性(Consistent):在事物開始和完成時,數據都必須保持一致狀態(最終結果)
    • 隔離性(Isolation):數據庫系統提供一定的隔離機制,保證事物在不受外部并發操作影響的“獨立”環境執行(鎖)
    • 持久性(Durable):事物完成之后,它對于數據的修改是永久的,即使出現系統故障也能夠保持(redolog )

    2、并發事物帶來的問題
    相對于串行來說呢,并發事物處理能力大大增加了數據庫資源的利用率,提高數據庫系統的事物吞吐量,從而可以支持更多用戶的并發操作,但與此同時,會帶來一些問題

    • 臟讀:
      記錄yy=1 A事務修改yy=2 未提交 , B事物讀取yy=2 ,A事務回滾 yy=1 ,這時B事務讀取的數據 就是臟數據
      示例:
    1. 創建表DROP TABLE IF EXISTS `test_innodb`;CREATE TABLE `test_innodb` (`id` bigint(20) NOT NULL,`name` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; 2. 插入數據 insert into test_innodb values (1,'小智障'); 3. 開啟兩個navicat窗口 與上邊示例一樣 N1 和 N2 4. N1 設置事務級別set session transaction isolation level read uncommitted;SELECT @@tx_isolation; -- READ-UNCOMMITTED 5. N2設置事務級別 set session transaction isolation level read uncommitted;SELECT @@tx_isolation; -- READ-UNCOMMITTED 6. N1 開啟事務 更新數據 但不提交 -- 開啟事務start TRANSACTION;-- 更新數據 update test_innodb set name = '小可愛' where id=1; 7. N2 開啟事務 查詢數據 拿著結果去做了一些其他業務-- 開啟事務start TRANSACTION;-- 讀取數據select name from test_innodb where id=1; -- 小可愛 if (name == "小可愛") {sout("請她吃根雪糕");} 8. N2 提交 commit; 9. N1 回滾 ROLLBACK; 10. N1 查詢 select name from test_innodb where id=1; -- 小智障 11. 結果就是N2拿著自以為對的N1得事務過程中的數據 來進行了自己的業務操作結果N1 事務沒有成功 而是回滾了 出現了N2 讀取前 后 數據不一致
    • 不可重復讀:
      事務A 讀取一條記錄yy=1 , 事務B 修改yy=2 提交,
      事務A 又讀取一次yy=2 事務A兩次讀取的結果不一致
      示例:
    -- 接著上邊示例的表結構來 1. N1 開啟事務 讀取數據 -- 開啟事務 start TRANSACTION; -- 讀取數據 select name from test_innodb where id=1; -- 結果是 name=小智障 2. N2 開啟事務 修改數據 提交事務 -- 開啟事務 start TRANSACTION; -- 更新數據 update test_innodb set name = '小可愛' where id=1; -- 提交事務 commit ; 3. N1 又一次讀取數據 select name from test_innodb where id=1; -- 結果是 name=小可愛 4. N1 兩次讀取數據不一致 這就是不可重復讀5. N1 提交事務 commit;
    • 幻讀:
      事務A 查詢范圍r的數據 結果為10條
      事務B 在這個范圍R內加了幾條數據 提交
      事務A 又一次讀取這個范圍R內的數據 結果不是10
      兩次讀取的記錄數不一致,這就是幻讀

    示例:

    -- 接著上邊表結構 1. N1 開啟事務 查詢數據 -- 開啟事務 start TRANSACTION; -- 查詢數據 select * from test_innodb where name like '%小%' -- 只有一條數據2. N2 開啟事務 新增數據 提交事務 -- 開啟事務 start TRANSACTION; -- 新增數據 insert into test_innodb values (1,'小智障'); insert into test_innodb values (1,'小傻瓜'); insert into test_innodb values (1,'小小鳥'); -- 提交事務 commit;3. N1 查詢數據 -- 查詢數據 select * from test_innodb where name like '%小%' -- 有4條數據 出現幻讀 跟幻覺一樣 剛剛是1 現在是4
    臟讀不可重復讀幻讀
    read uncommitted 讀取未提交內容
    read committed 讀提交內容
    repeatable read可重復讀
    serializable 可串行化

    Mysql Innodb默認是 repeatable read

    • read uncommitted 讀取未提交內容
      所有事務都可以看到其他事務未提交的執行結果
    • read committed 讀提交內容
      一個事務只能看到已提交的事務的執行結果
    • repeatable read可重復讀
      Mysql默認事務隔離級別,事務A讀取一條數據后,事務B對這條數據進行了修改,并提交,事務A再次讀取這條數據還是原來的內容(解決了不可重復讀)
    • serializable 可串行化
      事務 串行執行

    可以通過檢查Innodb_row_lock狀態變量來分析系統上的行鎖的爭奪情況

    show status like 'innodb_row_lock%';


    如果Innodb_row_lock_waits 和 Innodb_row_lock_time_avg 的值比較大就是鎖爭用比較嚴重


    3、InnoDB的行鎖模式 及 加鎖方式
    共享鎖(s):
    又叫讀鎖
    允許一個事務去讀一行,阻止其他事務獲取相同數據集的排它鎖,
    若事務T1對數據對象O上加了S鎖,則事務T1可以讀取O,但是不能修改O
    其他事務只能對O加S鎖,不能加排它鎖 ,這保證了其他事務可以讀O 但是不能修改O
    排它鎖(x):
    又叫寫鎖
    允許獲取排它鎖的事務更新數據,阻止其他事務獲取相同數據對象的排它鎖和共享鎖,
    若事務T1 對對象O 加上排它鎖,則事務T1可以讀取對象&修改對象,其他事務不能對O 加任何鎖

    Mysql的InnoDB引擎默認的修改數據語句:
    update delete insert 都會自動給涉及到的數據加上排它鎖
    select語句不會加任何類型的鎖,
    如果select加排它鎖可以用select * from table_name for update
    如果select加共享鎖 可以用 select * from table_name lock in share mode

    所以:加了排它鎖的數據行,在其他事務是不能修改數據的,也不能通過for update和 lock in share mode 鎖的方式查詢數據
    ,但是可以直接通過select * from table_name 查詢數據,因為普通的sleect沒有任何鎖限制

    Innodb行鎖是通過給索引 上的索引項來實現的,
    這點mysql與oracle不同,oracle是通過數據塊中對應數據行加鎖來實現的。
    innodb這種行鎖實現特點意味著:只有通過索引條件檢索數據,innodb才會使用行級鎖,否則,innodb將使用表鎖

  • 不用索引條件查詢時 innodb使用的是表鎖 不是行鎖
  • DROP TABLE IF EXISTS `test_no_index`; CREATE TABLE `test_no_index` (`id` bigint(20) NOT NULL,`name` varchar(255) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;插入數據:insert into test_no_index values (1,'a'),(2,'b'),(3,'c') 還是老朋友 用N1 N2 1. N1 set @@autocommit=0; 2. N2 set @@autocommit=0; 3. N1 select * from test_no_index where id=1 for update 4. N2 select * from test_no_index where id=2 for update -- 阻塞了 5. N1 commit; 6. N2 不阻塞了 查詢出結果了 7. N1 select * from test_no_index where id=1 for update -- 阻塞 8. N2 commit 9. N1 阻塞結束 獲取鎖了
  • 帶索引的查詢條件 innodb使用行鎖
  • DROP TABLE IF EXISTS `test_use_index`; CREATE TABLE `test_use_index` (`id` bigint(20) NOT NULL,`name` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;insert into test_use_index values (1,'a'),(2,'b'),(3,'c') 1. N1 set @@autocommit=0; 2. N2 set @@autocommit=0; 3. N1 select * from test_use_index where id=1 for update 4. N2 select * from test_use_index where id=2 for update --不阻塞了
  • 因為mysql行鎖是鎖的索引 所以雖然訪問的是不同行的記錄 如果使用相同的索引,還是會沖突
  • 接著上邊的表結構: ALTER TABLE `test_use_index` ADD INDEX `index_name` (`name`) USING BTREE ;ALTER TABLE `test_use_index` DROP PRIMARY KEY;insert into test_use_index values('6','a'); select * from test_use_index

    1. N1 select * from test_use_index where name='a' and id=1 for update 2. N2 select * from test_use_index where name='a' and id=6 for update -- 鎖住了 3. 雖然兩條for update 不是同一條記錄 但是還是使用的是一個索引name:a

    總結

    以上是生活随笔為你收集整理的mysql优化 个人笔记 (mysql锁机制 ) 非礼勿扰 -m10的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。