當前位置:首頁 » 編程語言 » sql行鎖實現
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

sql行鎖實現

發布時間: 2022-12-11 16:40:50

A. Java如何實現對Mysql資料庫的行鎖

用以下sql語句就可以實現行鎖定,前提是innodb模式:
SELECT ... FOR UPDATE
或者
SELECT ... LOCK IN SHARE MODE

B. SQL SERVER 中如何使用行鎖 為什麼我寫的行鎖鎖不住啊高手快來吧

給你個最詳細的吧 可能有你要的內容
鎖的概述

一. 為什麼要引入鎖

多個用戶同時對資料庫的並發操作時會帶來以下數據不一致的問題:

丟失更新
A,B兩個用戶讀同一數據並進行修改,其中一個用戶的修改結果破壞了另一個修改的結果,比如訂票系統

臟讀
A用戶修改了數據,隨後B用戶又讀出該數據,但A用戶因為某些原因取消了對數據的修改,數據恢復原值,此時B得到的數據就與資料庫內的數據產生了不一致

不可重復讀
A用戶讀取數據,隨後B用戶讀出該數據並修改,此時A用戶再讀取數據時發現前後兩次的值不一致

並發控制的主要方法是封鎖,鎖就是在一段時間內禁止用戶做某些操作以避免產生數據不一致

二 鎖的分類

鎖的類別有兩種分法:

1. 從資料庫系統的角度來看:分為獨占鎖(即排它鎖),共享鎖和更新鎖

MS-SQL Server 使用以下資源鎖模式。

鎖模式 描述
共享 (S) 用於不更改或不更新數據的操作(只讀操作),如 SELECT 語句。
更新 (U) 用於可更新的資源中。防止當多個會話在讀取、鎖定以及隨後可能進行的資源更新時發生常見形式的死鎖。
排它 (X) 用於數據修改操作,例如 INSERT、UPDATE 或 DELETE。確保不會同時同一資源進行多重更新。
意向鎖 用於建立鎖的層次結構。意向鎖的類型為:意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
架構鎖 在執行依賴於表架構的操作時使用。架構鎖的類型為:架構修改 (Sch-M) 和架構穩定性 (Sch-S)。
大容量更新 (BU) 向表中大容量復制數據並指定了 TABLOCK 提示時使用。

共享鎖
共享 (S) 鎖允許並發事務讀取 (SELECT) 一個資源。資源上存在共享 (S) 鎖時,任何其它事務都不能修改數據。一旦已經讀取數據,便立即釋放資源上的共享 (S) 鎖,除非將事務隔離級別設置為可重復讀或更高級別,或者在事務生存周期內用鎖定提示保留共享 (S) 鎖。

更新鎖
更新 (U) 鎖可以防止通常形式的死鎖。一般更新模式由一個事務組成,此事務讀取記錄,獲取資源(頁或行)的共享 (S) 鎖,然後修改行,此操作要求鎖轉換為排它 (X) 鎖。如果兩個事務獲得了資源上的共享模式鎖,然後試圖同時更新數據,則一個事務嘗試將鎖轉換為排它 (X) 鎖。共享模式到排它鎖的轉換必須等待一段時間,因為一個事務的排它鎖與其它事務的共享模式鎖不兼容;發生鎖等待。第二個事務試圖獲取排它 (X) 鎖以進行更新。由於兩個事務都要轉換為排它 (X) 鎖,並且每個事務都等待另一個事務釋放共享模式鎖,因此發生死鎖。

若要避免這種潛在的死鎖問題,請使用更新 (U) 鎖。一次只有一個事務可以獲得資源的更新 (U) 鎖。如果事務修改資源,則更新 (U) 鎖轉換為排它 (X) 鎖。否則,鎖轉換為共享鎖。

排它鎖
排它 (X) 鎖可以防止並發事務對資源進行訪問。其它事務不能讀取或修改排它 (X) 鎖鎖定的數據。

意向鎖
意向鎖表示 SQL Server 需要在層次結構中的某些底層資源上獲取共享 (S) 鎖或排它 (X) 鎖。例如,放置在表級的共享意向鎖表示事務打算在表中的頁或行上放置共享 (S) 鎖。在表級設置意向鎖可防止另一個事務隨後在包含那一頁的表上獲取排它 (X) 鎖。意向鎖可以提高性能,因為 SQL Server 僅在表級檢查意向鎖來確定事務是否可以安全地獲取該表上的鎖。而無須檢查表中的每行或每頁上的鎖以確定事務是否可以鎖定整個表。

意向鎖包括意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。

鎖模式 描述
意向共享 (IS) 通過在各資源上放置 S 鎖,表明事務的意向是讀取層次結構中的部分(而不是全部)底層資源。
意向排它 (IX) 通過在各資源上放置 X 鎖,表明事務的意向是修改層次結構中的部分(而不是全部)底層資源。IX 是 IS 的超集。
與意向排它共享 (SIX) 通過在各資源上放置 IX 鎖,表明事務的意向是讀取層次結構中的全部底層資源並修改部分(而不是全部)底層資源。允許頂層資源上的並發 IS 鎖。例如,表的 SIX 鎖在表上放置一個 SIX 鎖(允許並發 IS 鎖),在當前所修改頁上放置 IX 鎖(在已修改行上放置 X 鎖)。雖然每個資源在一段時間內只能有一個 SIX 鎖,以防止其它事務對資源進行更新,但是其它事務可以通過獲取表級的 IS 鎖來讀取層次結構中的底層資源。

獨占鎖:只允許進行鎖定操作的程序使用,其他任何對他的操作均不會被接受。執行數據更新命令時,SQL Server會自動使用獨占鎖。當對象上有其他鎖存在時,無法對其加獨占鎖。
共享鎖:共享鎖鎖定的資源可以被其他用戶讀取,但其他用戶無法修改它,在執行Select時,SQL Server會對對象加共享鎖。
更新鎖:當SQL Server准備更新數據時,它首先對數據對象作更新鎖鎖定,這樣數據將不能被修改,但可以讀取。等到SQL Server確定要進行更新數據操作時,他會自動將更新鎖換為獨占鎖,當對象上有其他鎖存在時,無法對其加更新鎖。

2. 從程序員的角度看:分為樂觀鎖和悲觀鎖。
樂觀鎖:完全依靠資料庫來管理鎖的工作。
悲觀鎖:程序員自己管理數據或對象上的鎖處理。

MS-SQLSERVER 使用鎖在多個同時在資料庫內執行修改的用戶間實現悲觀並發控制

三 鎖的粒度
鎖粒度是被封鎖目標的大小,封鎖粒度小則並發性高,但開銷大,封鎖粒度大則並發性低但開銷小

SQL Server支持的鎖粒度可以分為為行、頁、鍵、鍵范圍、索引、表或資料庫獲取鎖

資源 描述
RID 行標識符。用於單獨鎖定表中的一行。
鍵 索引中的行鎖。用於保護可串列事務中的鍵范圍。
頁 8 千位元組 (KB) 的數據頁或索引頁。
擴展盤區 相鄰的八個數據頁或索引頁構成的一組。
表 包括所有數據和索引在內的整個表。
DB 資料庫。

四 鎖定時間的長短

鎖保持的時間長度為保護所請求級別上的資源所需的時間長度。

用於保護讀取操作的共享鎖的保持時間取決於事務隔離級別。採用 READ COMMITTED 的默認事務隔離級別時,只在讀取頁的期間內控制共享鎖。在掃描中,直到在掃描內的下一頁上獲取鎖時才釋放鎖。如果指定 HOLDLOCK 提示或者將事務隔離級別設置為 REPEATABLE READ 或 SERIALIZABLE,則直到事務結束才釋放鎖。

根據為游標設置的並發選項,游標可以獲取共享模式的滾動鎖以保護提取。當需要滾動鎖時,直到下一次提取或關閉游標(以先發生者為准)時才釋放滾動鎖。但是,如果指定 HOLDLOCK,則直到事務結束才釋放滾動鎖。

用於保護更新的排它鎖將直到事務結束才釋放。
如果一個連接試圖獲取一個鎖,而該鎖與另一個連接所控制的鎖沖突,則試圖獲取鎖的連接將一直阻塞到:

將沖突鎖釋放而且連接獲取了所請求的鎖。

連接的超時間隔已到期。默認情況下沒有超時間隔,但是一些應用程序設置超時間隔以防止無限期等待

五 SQL Server 中鎖的自定義

1 處理死鎖和設置死鎖優先順序

死鎖就是多個用戶申請不同封鎖,由於申請者均擁有一部分封鎖權而又等待其他用戶擁有的部分封鎖而引起的無休止的等待

可以使用SET DEADLOCK_PRIORITY控制在發生死鎖情況時會話的反應方式。如果兩個進程都鎖定數據,並且直到其它進程釋放自己的鎖時,每個進程才能釋放自己的鎖,即發生死鎖情況。

2 處理超時和設置鎖超時持續時間。

@@LOCK_TIMEOUT 返回當前會話的當前鎖超時設置,單位為毫秒

SET LOCK_TIMEOUT 設置允許應用程序設置語句等待阻塞資源的最長時間。當語句等待的時間大於 LOCK_TIMEOUT 設置時,系統將自動取消阻塞的語句,並給應用程序返回"已超過了鎖請求超時時段"的 1222 號錯誤信息

示例
下例將鎖超時期限設置為 1,800 毫秒。
SET LOCK_TIMEOUT 1800

3) 設置事務隔離級別。

4 ) 對 SELECT、INSERT、UPDATE 和 DELETE 語句使用表級鎖定提示。

5) 配置索引的鎖定粒度
可以使用 sp_indexoption 系統存儲過程來設置用於索引的鎖定粒度

六 查看鎖的信息

1 執行 EXEC SP_LOCK 報告有關鎖的信息
2 查詢分析器中按Ctrl+2可以看到鎖的信息

七 使用注意事項

如何避免死鎖
1 使用事務時,盡量縮短事務的邏輯處理過程,及早提交或回滾事務;
2 設置死鎖超時參數為合理范圍,如:3分鍾-10分種;超過時間,自動放棄本次操作,避免進程懸掛;
3 優化程序,檢查並避免死鎖現象出現;
4 .對所有的腳本和SP都要仔細測試,在正是版本之前。
5 所有的SP都要有錯誤處理(通過@error)
6 一般不要修改SQL SERVER事務的默認級別。不推薦強行加鎖

解決問題 如何對行 表 資料庫加鎖

八 幾個有關鎖的問題

1 如何鎖一個表的某一行

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT * FROM table ROWLOCK WHERE id = 1

2 鎖定資料庫的一個表

SELECT * FROM table WITH (HOLDLOCK)

加鎖語句:
sybase:
update 表 set col1=col1 where 1=0 ;
MSSQL:
select col1 from 表 (tablockx) where 1=0 ;
oracle:
LOCK TABLE 表 IN EXCLUSIVE MODE ;
加鎖後其它人不可操作,直到加鎖用戶解鎖,用commit或rollback解鎖

幾個例子幫助大家加深印象
設table1(A,B,C)
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3

1)排它鎖
新建兩個連接
在第一個連接中執行以下語句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran
在第二個連接中執行以下語句
begin tran
select * from table1
where B='b2'
commit tran

若同時執行上述兩個語句,則select查詢必須等待update執行完畢才能執行即要等待30秒

2)共享鎖
在第一個連接中執行以下語句
begin tran
select * from table1 holdlock -holdlock人為加鎖
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran

在第二個連接中執行以下語句
begin tran
select A,C from table1
where B='b2'
update table1
set A='aa'
where B='b2'
commit tran

若同時執行上述兩個語句,則第二個連接中的select查詢可以執行
而update必須等待第一個事務釋放共享鎖轉為排它鎖後才能執行 即要等待30秒

3)死鎖
增設table2(D,E)
D E
d1 e1
d2 e2
在第一個連接中執行以下語句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30'
update table2
set D='d5'
where E='e1'
commit tran

在第二個連接中執行以下語句
begin tran
update table2
set D='d5'
where E='e1'
waitfor delay '00:00:10'
update table1
set A='aa'
where B='b2'
commit tran

同時執行,系統會檢測出死鎖,並中止進程

補充一點:
Sql Server2000支持的表級鎖定提示

HOLDLOCK 持有共享鎖,直到整個事務完成,應該在被鎖對象不需要時立即釋放,等於SERIALIZABLE事務隔離級別

NOLOCK 語句執行時不發出共享鎖,允許臟讀 ,等於 READ UNCOMMITTED事務隔離級別

PAGLOCK 在使用一個表鎖的地方用多個頁鎖

READPAST 讓sql server跳過任何鎖定行,執行事務,適用於READ UNCOMMITTED事務隔離級別只跳過RID鎖,不跳過頁,區域和表鎖

ROWLOCK 強制使用行鎖

TABLOCKX 強制使用獨占表級鎖,這個鎖在事務期間阻止任何其他事務使用這個表

UPLOCK 強制在讀表時使用更新而不用共享鎖

應用程序鎖:
應用程序鎖就是客戶端代碼生成的鎖,而不是sql server本身生成的鎖

處理應用程序鎖的兩個過程

sp_getapplock 鎖定應用程序資源

sp_releaseapplock 為應用程序資源解鎖

注意: 鎖定資料庫的一個表的區別

SELECT * FROM table WITH (HOLDLOCK) 其他事務可以讀取表,但不能更新刪除

SELECT * FROM table WITH (TABLOCKX) 其他事務不能讀取表,更新和刪除
參考資料:

C. 如何在SQLServer中鎖定某行記錄

鎖的概述

一. 為什麼要引入鎖
多個用戶同時對資料庫的並發操作時會帶來以下數據不一致的問題:
丟失更新
A,B兩個用戶讀同一數據並進行修改,其中一個用戶的修改結果破壞了另一個修改的結果,比如訂票系統
臟讀
A用戶修改了數據,隨後B用戶又讀出該數據,但A用戶因為某些原因取消了對數據的修改,數據恢復原值,此時B得到的數據就與資料庫內的數據產生了不一致
不可重復讀
A用戶讀取數據,隨後B用戶讀出該數據並修改,此時A用戶再讀取數據時發現前後兩次的值不一致
並發控制的主要方法是封鎖,鎖就是在一段時間內禁止用戶做某些操作以避免產生數據不一致
二 鎖的分類
鎖的類別有兩種分法:
1. 從資料庫系統的角度來看:分為獨占鎖(即排它鎖),共享鎖和更新鎖
MS SQL Server 使用以下資源鎖模式。
鎖模式 描述
共享 (S) 用於不更改或不更新數據的操作(只讀操作),如 SELECT 語句。
更新 (U) 用於可更新的資源中。防止當多個會話在讀取、鎖定以及隨後可能進行的資源更新時發生常見形式的死鎖。
排它 (X) 用於數據修改操作,例如 INSERT、UPDATE 或 DELETE。確保不會同時同一資源進行多重更新。
意向鎖 用於建立鎖的層次結構。意向鎖的類型為:意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
架構鎖 在執行依賴於表架構的操作時使用。架構鎖的類型為:架構修改 (Sch-M) 和架構穩定性 (Sch-S)。
大容量更新 (BU) 向表中大容量復制數據並指定了 TABLOCK 提示時使用。
共享鎖
共享 (S) 鎖允許並發事務讀取 (SELECT) 一個資源。資源上存在共享 (S) 鎖時,任何其它事務都不能修改數據。一旦已經讀取數據,便立即釋放資源上的共享 (S) 鎖,除非將事務隔離級別設置為可重復讀或更高級別,或者在事務生存周期內用鎖定提示保留共享 (S) 鎖。
更新鎖
更新 (U) 鎖可以防止通常形式的死鎖。一般更新模式由一個事務組成,此事務讀取記錄,獲取資源(頁或行)的共享 (S) 鎖,然後修改行,此操作要求鎖轉換為排它 (X) 鎖。如果兩個事務獲得了資源上的共享模式鎖,然後試圖同時更新數據,則一個事務嘗試將鎖轉換為排它 (X) 鎖。共享模式到排它鎖的轉換必須等待一段時間,因為一個事務的排它鎖與其它事務的共享模式鎖不兼容;發生鎖等待。第二個事務試圖獲取排它 (X) 鎖以進行更新。由於兩個事務都要轉換為排它 (X) 鎖,並且每個事務都等待另一個事務釋放共享模式鎖,因此發生死鎖。
若要避免這種潛在的死鎖問題,請使用更新 (U) 鎖。一次只有一個事務可以獲得資源的更新 (U) 鎖。如果事務修改資源,則更新 (U) 鎖轉換為排它 (X) 鎖。否則,鎖轉換為共享鎖。
排它鎖
排它 (X) 鎖可以防止並發事務對資源進行訪問。其它事務不能讀取或修改排它 (X) 鎖鎖定的數據。
意向鎖
意向鎖表示 SQL Server 需要在層次結構中的某些底層資源上獲取共享 (S) 鎖或排它 (X) 鎖。例如,放置在表級的共享意向鎖表示事務打算在表中的頁或行上放置共享 (S) 鎖。在表級設置意向鎖可防止另一個事務隨後在包含那一頁的表上獲取排它 (X) 鎖。意向鎖可以提高性能,因為 SQL Server 僅在表級檢查意向鎖來確定事務是否可以安全地獲取該表上的鎖。而無須檢查表中的每行或每頁上的鎖以確定事務是否可以鎖定整個表。
意向鎖包括意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
鎖模式
描述
意向共享 (IS) 通過在各資源上放置 S 鎖,表明事務的意向是讀取層次結構中的部分(而不是全部)底層資源。
意向排它 (IX) 通過在各資源上放置 X 鎖,表明事務的意向是修改層次結構中的部分(而不是全部)底層資源。IX 是 IS 的超集。與意向排它共享 (SIX) 通過在各資源上放置 IX 鎖,表明事務的意向是讀取層次結構中的全部底層資源並修改部分(而不是全部)底層資源。允許頂層資源上的並發 IS 鎖。例如,表的 SIX 鎖在表上放置一個 SIX 鎖(允許並發 IS 鎖),在當前所修改頁上放置 IX 鎖(在已修改行上放置 X 鎖)。雖然每個資源在一段時間內只能有一個 SIX 鎖,以防止其它事務對資源進行更新,但是其它事務可以通過獲取表級的 IS 鎖來讀取層次結構中的底層資源。
獨占鎖:只允許進行鎖定操作的程序使用,其他任何對他的操作均不會被接受。執行數據更新命令時,SQL Server會自動使用獨占鎖。當對象上有其他鎖存在時,無法對其加獨占鎖。
共享鎖:共享鎖鎖定的資源可以被其他用戶讀取,但其他用戶無法修改它,在執行Select時,SQL Server會對對象加共享鎖。
更新鎖:當SQL Server准備更新數據時,它首先對數據對象作更新鎖鎖定,這樣數據將不能被修改,但可以讀取。等到SQL Server確定要進行更新數據操作時,他會自動將更新鎖換為獨占鎖,當對象上有其他鎖存在時,無法對其加更新鎖。
2. 從程序員的角度看:分為樂觀鎖和悲觀鎖。
樂觀鎖:完全依靠資料庫來管理鎖的工作。
悲觀鎖:程序員自己管理數據或對象上的鎖處理。
MS SQL Server 使用鎖在多個同時在資料庫內執行修改的用戶間實現悲觀並發控制
三 鎖的粒度
鎖粒度是被封鎖目標的大小,封鎖粒度小則並發性高,但開銷大,封鎖粒度大則並發性低但開銷小
SQL Server支持的鎖粒度可以分為為行、頁、鍵、鍵范圍、索引、表或資料庫獲取鎖
資源描述
RID 行標識符。用於單獨鎖定表中的一行。
鍵 索引中的行鎖。用於保護可串列事務中的鍵范圍。
頁 8 千位元組 (KB) 的數據頁或索引頁。
擴展盤區 相鄰的八個數據頁或索引頁構成的一組。
表 包括所有數據和索引在內的整個表。
DB 資料庫。
四 鎖定時間的長短
鎖保持的時間長度為保護所請求級別上的資源所需的時間長度。
用於保護讀取操作的共享鎖的保持時間取決於事務隔離級別。採用 READ COMMITTED 的默認事務隔離級別時,只在讀取頁的期間內控制共享鎖。在掃描中,直到在掃描內的下一頁上獲取鎖時才釋放鎖。如果指定 HOLDLOCK 提示或者將事務隔離級別設置為 REPEATABLE READ 或 SERIALIZABLE,則直到事務結束才釋放鎖。
根據為游標設置的並發選項,游標可以獲取共享模式的滾動鎖以保護提取。當需要滾動鎖時,直到下一次提取或關閉游標(以先發生者為准)時才釋放滾動鎖。但是,如果指定 HOLDLOCK,則直到事務結束才釋放滾動鎖。
用於保護更新的排它鎖將直到事務結束才釋放。
如果一個連接試圖獲取一個鎖,而該鎖與另一個連接所控制的鎖沖突,則試圖獲取鎖的連接將一直阻塞到:
將沖突鎖釋放而且連接獲取了所請求的鎖。
連接的超時間隔已到期。默認情況下沒有超時間隔,但是一些應用程序設置超時間隔以防止無限期等待
五 SQL Server 中鎖的自定義
1 處理死鎖和設置死鎖優先順序
死鎖就是多個用戶申請不同封鎖,由於申請者均擁有一部分封鎖權而又等待其他用戶擁有的部分封鎖而引起的無休止的等待可以使用SET DEADLOCK_PRIORITY控制在發生死鎖情況時會話的反應方式。如果兩個進程都鎖定數據,並且直到其它進程釋放自己的鎖時,每個進程才能釋放自己的鎖,即發生死鎖情況。
2 處理超時和設置鎖超時持續時間。
@@LOCK_TIMEOUT 返回當前會話的當前鎖超時設置,單位為毫秒
SET LOCK_TIMEOUT 設置允許應用程序設置語句等待阻塞資源的最長時間。當語句等待的時間大於 LOCK_TIMEOUT 設置時,系統將自動取消阻塞的語句,並給應用程序返回"已超過了鎖請求超時時段"的 1222 號錯誤信息
示例
下例將鎖超時期限設置為 1,800 毫秒。
SET LOCK_TIMEOUT 1800

3) 設置事務隔離級別。
4 ) 對 SELECT、INSERT、UPDATE 和 DELETE 語句使用表級鎖定提示。
5) 配置索引的鎖定粒度
可以使用 sp_indexoption 系統存儲過程來設置用於索引的鎖定粒度
六 查看鎖的信息 1 執行 EXEC SP_LOCK 報告有關鎖的信息
2 查詢分析器中按Ctrl+2可以看到鎖的信息
七 使用注意事項
如何避免死鎖
1 使用事務時,盡量縮短事務的邏輯處理過程,及早提交或回滾事務;
2 設置死鎖超時參數為合理范圍,如:3分鍾-10分種;超過時間,自動放棄本次操作,避免進程懸掛;
3 優化程序,檢查並避免死鎖現象出現;
4 .對所有的腳本和SP都要仔細測試,在正是版本之前。
5 所有的SP都要有錯誤處理(通過@error)
6 一般不要修改SQL Server事務的默認級別。不推薦強行加鎖
八 幾個有關鎖的問題
1 如何鎖一個表的某一行
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDSELECT * FROM table ROWLOCK WHERE id =
1

2 鎖定資料庫的一個表
SELECT * FROM table WITH (HOLDLOCK)

加鎖語句:
sybase:update 表 set col1=col1 where 1=0 ;MS SQL:select col1 from 表 (tablockx) where 1=0 ;oracle:LOCK TABLE 表 IN EXCLUSIVE MODE ;

加鎖後其它人不可操作,直到加鎖用戶解鎖,用commit或rollback解鎖

幾個例子幫助大家加深印象,設table1(A,B,C)
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3

1)排它鎖
新建兩個連接,在第一個連接中執行以下語句
begin tranupdate table1set A='aa'where B='b2'waitfor delay '00:00:30'
--等待30秒commit tran

在第二個連接中執行以下語句
begin transelect * from table1where B='b2'commit tran

若同時執行上述兩個語句,則select查詢必須等待update執行完畢才能執行即要等待30秒
2)共享鎖
在第一個連接中執行以下語句
begin transelect * from table1 holdlock -holdlock人為加鎖where B='b2'waitfor delay '00:00:30'
--等待30秒commit tran

在第二個連接中執行以下語句
begin transelect A,C from table1where B='b2'update table1set A='aa'where B='b2'commit tran

若同時執行上述兩個語句,則第二個連接中的select查詢可以執行,而update必須等待第一個事務釋放共享鎖轉為排它鎖後才能執行 即要等待30秒
3)死鎖
增設table2(D,E)
D E

d1 e1
d2 e2

在第一個連接中執行以下語句
begin tranupdate table1set A='aa'where B='b2'waitfor delay '00:00:30'update table2set D='d5'where E='e1'commit tran

在第二個連接中執行以下語句
begin tranupdate table2set D='d5'where E='e1'waitfor delay '00:00:10'update table1set A='aa'where B='b2'commit tran

同時執行,系統會檢測出死鎖,並中止進程
補充一點:
SQL Server 2000支持的表級鎖定提示
HOLDLOCK 持有共享鎖,直到整個事務完成,應該在被鎖對象不需要時立即釋放,等於SERIALIZABLE事務隔離級別
NOLOCK 語句執行時不發出共享鎖,允許臟讀 ,等於 READ UNCOMMITTED事務隔離級別
PAGLOCK 在使用一個表鎖的地方用多個頁鎖
READPAST 讓SQL Server跳過任何鎖定行,執行事務,適用於READ UNCOMMITTED事務隔離級別只跳過RID鎖,不跳過頁,區域和表鎖
ROWLOCK 強制使用行鎖
TABLOCKX 強制使用獨占表級鎖,這個鎖在事務期間阻止任何其他事務使用這個表
UPLOCK 強制在讀表時使用更新而不用共享鎖
應用程序鎖:
應用程序鎖就是客戶端代碼生成的鎖,而不是SQL Server本身生成的鎖
處理應用程序鎖的兩個過程
sp_getapplock 鎖定應用程序資源
sp_releaseapplock 為應用程序資源解鎖
注意: 鎖定資料庫的一個表的區別
SELECT * FROM table WITH (HOLDLOCK) 其他事務可以讀取表,但不能更新刪除
SELECT * FROM table WITH (TABLOCKX) 其他事務不能讀取表,更新和刪除

D. 關於MySQL中的表鎖和行鎖

mysql行鎖和表鎖

鎖是計算機協調多個進程或純線程並發訪問某一資源的機制。在資料庫中,除傳統的計算資源(CPU、RAM、I/O)的爭用以外,數據也是一種供許多用戶共享的資源。如何保證數據並發訪問的一致性、有效性是所在有資料庫必須解決的一個問題,鎖沖突也是影響資料庫並發訪問性能的一個重要因素。從這個角度來說,鎖對資料庫而言顯得尤其重要,也更加復雜。

概述

相對其他資料庫而言,MySQL的鎖機制比較簡單,其最顯著的特點是不同的存儲引擎支持不同的鎖機制。

MySQL大致可歸納為以下3種鎖:

  1. 表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低。

  2. 行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。

  3. 頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並發度一般

    MySQL表級鎖的鎖模式(MyISAM)

    MySQL表級鎖有兩種模式:表共享鎖(Table Read Lock)和表獨占寫鎖(Table Write Lock)。

  1. 對MyISAM的讀操作,不會阻塞其他用戶對同一表請求,但會阻塞對同一表的寫請求;

  2. 對MyISAM的寫操作,則會阻塞其他用戶對同一表的讀和寫操作;

  3. MyISAM表的讀操作和寫操作之間,以及寫操作之間是串列的。

    當一個線程獲得對一個表的寫鎖後,只有持有鎖線程可以對表進行更新操作。其他線程的讀、寫操作都會等待,直到鎖被釋放為止。

    MySQL表級鎖的鎖模式

    MySQL的表鎖有兩種模式:表共享讀鎖(Table Read Lock)和表獨占寫鎖(Table Write Lock)。鎖模式的兼容如下表

    MySQL中的表鎖兼容性

    當前鎖模式/是否兼容/請求鎖模式

    讀鎖 是 是 否

    寫鎖 是 否 否

    可見,對MyISAM表的讀操作,不會阻塞其他用戶對同一表的讀請求,但會阻塞對同一表的寫請求;對MyISAM表的寫操作,則會阻塞其他用戶對同一表的讀和寫請求;MyISAM表的讀和寫操作之間,以及寫和寫操作之間是串列的!(當一線程獲得對一個表的寫鎖後,只有持有鎖的線程可以對表進行更新操作。其他線程的讀、寫操作都會等待,直到鎖被釋放為止。)

    如何加表鎖

    MyISAM在執行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,在執行更新操作(UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖,這個過程並不需要用戶干預,因此用戶一般不需要直接用LOCK TABLE命令給MyISAM表顯式加鎖。在本書的示例中,顯式加鎖基本上都是為了方便而已,並非必須如此。

    給MyISAM表顯示加鎖,一般是為了一定程度模擬事務操作,實現對某一時間點多個表的一致性讀取。

    要特別說明以下兩點內容。

  • 上面的例子在LOCK TABLES時加了『local』選項,其作用就是在滿足MyISAM表並發插入條件的情況下,允許其他用戶在表尾插入記錄

  • 在用LOCKTABLES給表顯式加表鎖是時,必須同時取得所有涉及表的鎖,並且MySQL支持鎖升級。也就是說,在執行LOCK TABLES後,只能訪問顯式加鎖的這些表,不能訪問未加鎖的表;同時,如果加的是讀鎖,那麼只能執行查詢操作,而不能執行更新操作。其實,在自動加鎖的情況下也基本如此,MySQL問題一次獲得SQL語句所需要的全部鎖。這也正是MyISAM表不會出現死鎖(Deadlock Free)的原因

  • 一個session使用LOCK TABLE 命令給表film_text加了讀鎖,這個session可以查詢鎖定表中的記錄,但更新或訪問其他表都會提示錯誤;同時,另外一個session可以查詢表中的記錄,但更新就會出現鎖等待。

    當使用LOCK TABLE時,不僅需要一次鎖定用到的所有表,而且,同一個表在SQL語句中出現多少次,就要通過與SQL語句中相同的別名鎖多少次,否則也會出錯!

    並發鎖

    在一定條件下,MyISAM也支持查詢和操作的並發進行。

    MyISAM存儲引擎有一個系統變數concurrent_insert,專門用以控制其並發插入的行為,其值分別可以為0、1或2。

  • 當concurrent_insert設置為0時,不允許並發插入。

  • 當concurrent_insert設置為1時,如果MyISAM允許在一個讀表的同時,另一個進程從表尾插入記錄。這也是MySQL的默認設置。

  • 當concurrent_insert設置為2時,無論MyISAM表中有沒有空洞,都允許在表尾插入記錄,都允許在表尾並發插入記錄。

  • 可以利用MyISAM存儲引擎的並發插入特性,來解決應用中對同一表查詢和插入鎖爭用。例如,將concurrent_insert系統變數為2,總是允許並發插入;同時,通過定期在系統空閑時段執行OPTIONMIZE TABLE語句來整理空間碎片,收到因刪除記錄而產生的中間空洞。

    MyISAM的鎖調度

    前面講過,MyISAM存儲引擎的讀和寫鎖是互斥,讀操作是串列的。那麼,一個進程請求某個MyISAM表的讀鎖,同時另一個進程也請求同一表的寫鎖,MySQL如何處理呢?答案是寫進程先獲得鎖。不僅如此,即使讀進程先請求先到鎖等待隊列,寫請求後到,寫鎖也會插到讀請求之前!這是因為MySQL認為寫請求一般比讀請求重要。這也正是MyISAM表不太適合於有大量更新操作和查詢操作應用的原因,因為,大量的更新操作會造成查詢操作很難獲得讀鎖,從而可能永遠阻塞。這種情況有時可能會變得非常糟糕!幸好我們可以通過一些設置來調節MyISAM的調度行為。

  • 通過指定啟動參數low-priority-updates,使MyISAM引擎默認給予讀請求以優先的權利。

  • 通過執行命令SET LOW_PRIORITY_UPDATES=1,使該連接發出的更新請求優先順序降低。

  • 通過指定INSERT、UPDATE、DELETE語句的LOW_PRIORITY屬性,降低該語句的優先順序。

  • 雖然上面3種方法都是要麼更新優先,要麼查詢優先的方法,但還是可以用其來解決查詢相對重要的應用(如用戶登錄系統)中,讀鎖等待嚴重的問題。

    另外,MySQL也提供了一種折中的辦法來調節讀寫沖突,即給系統參數max_write_lock_count設置一個合適的值,當一個表的讀鎖達到這個值後,MySQL變暫時將寫請求的優先順序降低,給讀進程一定獲得鎖的機會。

    上面已經討論了寫優先調度機制和解決辦法。這里還要強調一點:一些需要長時間運行的查詢操作,也會使寫進程「餓死」!因此,應用中應盡量避免出現長時間運行的查詢操作,不要總想用一條SELECT語句來解決問題。因為這種看似巧妙的SQL語句,往往比較復雜,執行時間較長,在可能的情況下可以通過使用中間表等措施對SQL語句做一定的「分解」,使每一步查詢都能在較短時間完成,從而減少鎖沖突。如果復雜查詢不可避免,應盡量安排在資料庫空閑時段執行,比如一些定期統計可以安排在夜間執行。

    InnoDB鎖問題

    InnoDB與MyISAM的最大不同有兩點:一是支持事務(TRANSACTION);二是採用了行級鎖。

    行級鎖和表級鎖本來就有許多不同之處,另外,事務的引入也帶來了一些新問題。

    1.事務(Transaction)及其ACID屬性

    事務是由一組SQL語句組成的邏輯處理單元,事務具有4屬性,通常稱為事務的ACID屬性。

  • 原性性(Actomicity):事務是一個原子操作單元,其對數據的修改,要麼全都執行,要麼全都不執行。

  • 一致性(Consistent):在事務開始和完成時,數據都必須保持一致狀態。這意味著所有相關的數據規則都必須應用於事務的修改,以操持完整性;事務結束時,所有的內部數據結構(如B樹索引或雙向鏈表)也都必須是正確的。

  • 隔離性(Isolation):資料庫系統提供一定的隔離機制,保證事務在不受外部並發操作影響的「獨立」環境執行。這意味著事務處理過程中的中間狀態對外部是不可見的,反之亦然。

  • 持久性(Durable):事務完成之後,它對於數據的修改是永久性的,即使出現系統故障也能夠保持。

  • 2.並發事務帶來的問題

    相對於串列處理來說,並發事務處理能大大增加資料庫資源的利用率,提高資料庫系統的事務吞吐量,從而可以支持可以支持更多的用戶。但並發事務處理也會帶來一些問題,主要包括以下幾種情況。

  • 更新丟失(Lost Update):當兩個或多個事務選擇同一行,然後基於最初選定的值更新該行時,由於每個事務都不知道其他事務的存在,就會發生丟失更新問題——最後的更新覆蓋了其他事務所做的更新。例如,兩個編輯人員製作了同一文檔的電子副本。每個編輯人員獨立地更改其副本,然後保存更改後的副本,這樣就覆蓋了原始文檔。最後保存其更改保存其更改副本的編輯人員覆蓋另一個編輯人員所做的修改。如果在一個編輯人員完成並提交事務之前,另一個編輯人員不能訪問同一文件,則可避免此問題

  • 臟讀(Dirty Reads):一個事務正在對一條記錄做修改,在這個事務並提交前,這條記錄的數據就處於不一致狀態;這時,另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些「臟」的數據,並據此做進一步的處理,就會產生未提交的數據依賴關系。這種現象被形象地叫做「臟讀」。

  • 不可重復讀(Non-Repeatable Reads):一個事務在讀取某些數據已經發生了改變、或某些記錄已經被刪除了!這種現象叫做「不可重復讀」。

  • 幻讀(Phantom Reads):一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務插入了滿足其查詢條件的新數據,這種現象就稱為「幻讀」。

  • 3.事務隔離級別

    在並發事務處理帶來的問題中,「更新丟失」通常應該是完全避免的。但防止更新丟失,並不能單靠資料庫事務控制器來解決,需要應用程序對要更新的數據加必要的鎖來解決,因此,防止更新丟失應該是應用的責任。

    「臟讀」、「不可重復讀」和「幻讀」,其實都是資料庫讀一致性問題,必須由資料庫提供一定的事務隔離機制來解決。資料庫實現事務隔離的方式,基本可以分為以下兩種。

    一種是在讀取數據前,對其加鎖,阻止其他事務對數據進行修改。

    另一種是不用加任何鎖,通過一定機制生成一個數據請求時間點的一致性數據快照(Snapshot),並用這個快照來提供一定級別(語句級或事務級)的一致性讀取。從用戶的角度,好像是資料庫可以提供同一數據的多個版本,因此,這種技術叫做數據多版本並發控制(MultiVersion Concurrency Control,簡稱MVCC或MCC),也經常稱為多版本資料庫。

    資料庫的事務隔離級別越嚴格,並發副作用越小,但付出的代價也就越大,因為事務隔離實質上就是使事務在一定程度上「串列化」進行,這顯然與「並發」是矛盾的,同時,不同的應用對讀一致性和事務隔離程度的要求也是不同的,比如許多應用對「不可重復讀」和「幻讀」並不敏感,可能更關心數據並發訪問的能力。

    為了解決「隔離」與「並發」的矛盾,ISO/ANSI SQL92定義了4個事務隔離級別,每個級別的隔離程度不同,允許出現的副作用也不同,應用可以根據自己業務邏輯要求,通過選擇不同的隔離級別來平衡"隔離"與"並發"的矛盾

    事務4種隔離級別比較

    隔離級別/讀數據一致性及允許的並發副作用 讀數據一致性 臟讀 不可重復讀 幻讀

    未提交讀(Read uncommitted)

  • 最低級別,只能保證不讀取物理上損壞的數據 是 是 是

  • 已提交度(Read committed) 語句級 否 是 是

    可重復讀(Repeatable read) 事務級 否 否 是

    可序列化(Serializable) 最高級別,事務級 否 否 否

    最後要說明的是:各具體資料庫並不一定完全實現了上述4個隔離級別,例如,Oracle只提供Read committed和Serializable兩個標准級別,另外還自己定義的Read only隔離級別:SQL Server除支持上述ISO/ANSI SQL92定義的4個級別外,還支持一個叫做"快照"的隔離級別,但嚴格來說它是一個用MVCC實現的Serializable隔離級別。MySQL支持全部4個隔離級別,但在具體實現時,有一些特點,比如在一些隔離級下是採用MVCC一致性讀,但某些情況又不是。

    獲取InonoD行鎖爭用情況

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

    如果發現爭用比較嚴重,如Innodb_row_lock_waits和Innodb_row_lock_time_avg的值比較高,還可以通過設置InnoDB Monitors來進一步觀察發生鎖沖突的表、數據行等,並分析鎖爭用的原因。

    InnoDB的行鎖模式及加鎖方法

    InnoDB實現了以下兩種類型的行鎖。

  • 共享鎖(s):允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖。

  • 排他鎖(X):允許獲取排他鎖的事務更新數據,阻止其他事務取得相同的數據集共享讀鎖和排他寫鎖。

  • 另外,為了允許行鎖和表鎖共存,實現多粒度鎖機制,InnoDB還有兩種內部使用的意向鎖(Intention Locks),這兩種意向鎖都是表鎖。

    意向共享鎖(IS):事務打算給數據行共享鎖,事務在給一個數據行加共享鎖前必須先取得該表的IS鎖。

    意向排他鎖(IX):事務打算給數據行加排他鎖,事務在給一個數據行加排他鎖前必須先取得該表的IX鎖。

    InnoDB行鎖模式兼容性列表

    如果一個事務請求的鎖模式與當前的鎖兼容,InnoDB就請求的鎖授予該事務;反之,如果兩者兩者不兼容,該事務就要等待鎖釋放。

    意向鎖是InnoDB自動加的,不需用戶干預。對於UPDATE、DELETE和INSERT語句,InnoDB會自動給涉及及數據集加排他鎖(X);對於普通SELECT語句,InnoDB會自動給涉及數據集加排他鎖(X);對於普通SELECT語句,InnoDB不會任何鎖;事務可以通過以下語句顯示給記錄集加共享鎖或排鎖。

    共享鎖(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE

    排他鎖(X):SELECT * FROM table_name WHERE ...FOR UPDATE

    用SELECT .. IN SHARE MODE獲得共享鎖,主要用在需要數據依存關系時確認某行記錄是否存在,並確保沒有人對這個記錄進行UPDATE或者DELETE操作。但是如果當前事務也需要對該記錄進行更新操作,則很有可能造成死鎖,對於鎖定行記錄後需要進行更新操作的應用,應該使用SELECT ... FOR UPDATE方式獲取排他鎖。

    InnoDB行鎖實現方式

    InnoDB行鎖是通過索引上的索引項來實現的,這一點MySQL與Oracle不同,後者是通過在數據中對相應數據行加鎖來實現的。InnoDB這種行鎖實現特點意味者:只有通過索引條件檢索數據,InnoDB才會使用行級鎖,否則,InnoDB將使用表鎖!

    在實際應用中,要特別注意InnoDB行鎖的這一特性,不然的話,可能導致大量的鎖沖突,從而影響並發性能。

    什麼時候使用表鎖

    對於InnoDB表,在絕大部分情況下都應該使用行級鎖,因為事務和行鎖往往是我們之所以選擇InnoDB表的理由。但在個另特殊事務中,也可以考慮使用表級鎖。

  • 第一種情況是:事務需要更新大部分或全部數據,表又比較大,如果使用默認的行鎖,不僅這個事務執行效率低,而且可能造成其他事務長時間鎖等待和鎖沖突,這種情況下可以考慮使用表鎖來提高該事務的執行速度。

  • 第二種情況是:事務涉及多個表,比較復雜,很可能引起死鎖,造成大量事務回滾。這種情況也可以考慮一次性鎖定事務涉及的表,從而避免死鎖、減少資料庫因事務回滾帶來的開銷。

  • 當然,應用中這兩種事務不能太多,否則,就應該考慮使用MyISAM表。

    在InnoDB下 ,使用表鎖要注意以下兩點。

    (1)使用LOCK TALBES雖然可以給InnoDB加表級鎖,但必須說明的是,表鎖不是由InnoDB存儲引擎層管理的,而是由其上一層MySQL Server負責的,僅當autocommit=0、innodb_table_lock=1(默認設置)時,InnoDB層才能知道MySQL加的表鎖,MySQL Server才能感知InnoDB加的行鎖,這種情況下,InnoDB才能自動識別涉及表級鎖的死鎖;否則,InnoDB將無法自動檢測並處理這種死鎖。

    (2)在用LOCAK TABLES對InnoDB鎖時要注意,要將AUTOCOMMIT設為0,否則MySQL不會給表加鎖;事務結束前,不要用UNLOCAK TABLES釋放表鎖,因為UNLOCK TABLES會隱含地提交事務;COMMIT或ROLLBACK產不能釋放用LOCAK TABLES加的表級鎖,必須用UNLOCK TABLES釋放表鎖,正確的方式見如下語句。

    關於死鎖

    MyISAM表鎖是deadlock free的,這是因為MyISAM總是一次性獲得所需的全部鎖,要麼全部滿足,要麼等待,因此不會出現死鎖。但是在InnoDB中,除單個SQL組成的事務外,鎖是逐步獲得的,這就決定了InnoDB發生死鎖是可能的。

    發生死鎖後,InnoDB一般都能自動檢測到,並使一個事務釋放鎖並退回,另一個事務獲得鎖,繼續完成事務。但在涉及外部鎖,或涉及鎖的情況下,InnoDB並不能完全自動檢測到死鎖,這需要通過設置鎖等待超時參數innodb_lock_wait_timeout來解決。需要說明的是,這個參數並不是只用來解決死鎖問題,在並發訪問比較高的情況下,如果大量事務因無法立即獲取所需的鎖而掛起,會佔用大量計算機資源,造成嚴重性能問題,甚至拖垮資料庫。我們通過設置合適的鎖等待超時閾值,可以避免這種情況發生。

    通常來說,死鎖都是應用設計的問題,通過調整業務流程、資料庫對象設計、事務大小、以及訪問資料庫的SQL語句,絕大部分都可以避免。下面就通過實例來介紹幾種死鎖的常用方法。

    (1)在應用中,如果不同的程序會並發存取多個表,應盡量約定以相同的順序為訪問表,這樣可以大大降低產生死鎖的機會。如果兩個session訪問兩個表的順序不同,發生死鎖的機會就非常高!但如果以相同的順序來訪問,死鎖就可能避免。

    (2)在程序以批量方式處理數據的時候,如果事先對數據排序,保證每個線程按固定的順序來處理記錄,也可以大大降低死鎖的可能。

    (3)在事務中,如果要更新記錄,應該直接申請足夠級別的鎖,即排他鎖,而不應該先申請共享鎖,更新時再申請排他鎖,甚至死鎖。

    (4)在REPEATEABLE-READ隔離級別下,如果兩個線程同時對相同條件記錄用SELECT...ROR UPDATE加排他鎖,在沒有符合該記錄情況下,兩個線程都會加鎖成功。程序發現記錄尚不存在,就試圖插入一條新記錄,如果兩個線程都這么做,就會出現死鎖。這種情況下,將隔離級別改成READ COMMITTED,就可以避免問題。

    (5)當隔離級別為READ COMMITED時,如果兩個線程都先執行SELECT...FOR UPDATE,判斷是否存在符合條件的記錄,如果沒有,就插入記錄。此時,只有一個線程能插入成功,另一個線程會出現鎖等待,當第1個線程提交後,第2個線程會因主鍵重出錯,但雖然這個線程出錯了,卻會獲得一個排他鎖!這時如果有第3個線程又來申請排他鎖,也會出現死鎖。對於這種情況,可以直接做插入操作,然後再捕獲主鍵重異常,或者在遇到主鍵重錯誤時,總是執行ROLLBACK釋放獲得的排他鎖。

    盡管通過上面的設計和優化等措施,可以大減少死鎖,但死鎖很難完全避免。因此,在程序設計中總是捕獲並處理死鎖異常是一個很好的編程習慣。

    如果出現死鎖,可以用SHOW INNODB STATUS命令來確定最後一個死鎖產生的原因和改進措施。

    總結

    對於MyISAM的表鎖,主要有以下幾點

    (1)共享讀鎖(S)之間是兼容的,但共享讀鎖(S)和排他寫鎖(X)之間,以及排他寫鎖之間(X)是互斥的,也就是說讀和寫是串列的。

    (2)在一定條件下,MyISAM允許查詢和插入並發執行,我們可以利用這一點來解決應用中對同一表和插入的鎖爭用問題。

    (3)MyISAM默認的鎖調度機制是寫優先,這並不一定適合所有應用,用戶可以通過設置LOW_PRIPORITY_UPDATES參數,或在INSERT、UPDATE、DELETE語句中指定LOW_PRIORITY選項來調節讀寫鎖的爭用。

    (4)由於表鎖的鎖定粒度大,讀寫之間又是串列的,因此,如果更新操作較多,MyISAM表可能會出現嚴重的鎖等待,可以考慮採用InnoDB表來減少鎖沖突。

    對於InnoDB表,主要有以下幾點

    (1)InnoDB的行銷是基於索引實現的,如果不通過索引訪問數據,InnoDB會使用表鎖。

    (2)InnoDB間隙鎖機制,以及InnoDB使用間隙鎖的原因。

    (3)在不同的隔離級別下,InnoDB的鎖機制和一致性讀策略不同。

    (4)MySQL的恢復和復制對InnoDB鎖機制和一致性讀策略也有較大影響。

    (5)鎖沖突甚至死鎖很難完全避免。

    在了解InnoDB的鎖特性後,用戶可以通過設計和SQL調整等措施減少鎖沖突和死鎖,包括:

  • 盡量使用較低的隔離級別

  • 精心設計索引,並盡量使用索引訪問數據,使加鎖更精確,從而減少鎖沖突的機會。

  • 選擇合理的事務大小,小事務發生鎖沖突的幾率也更小。

  • 給記錄集顯示加鎖時,最好一次性請求足夠級別的鎖。比如要修改數據的話,最好直接申請排他鎖,而不是先申請共享鎖,修改時再請求排他鎖,這樣容易產生死鎖。

  • 不同的程序訪問一組表時,應盡量約定以相同的順序訪問各表,對一個表而言,盡可能以固定的順序存取表中的行。這樣可以大減少死鎖的機會。

  • 盡量用相等條件訪問數據,這樣可以避免間隙鎖對並發插入的影響。

  • 不要申請超過實際需要的鎖級別;除非必須,查詢時不要顯示加鎖。

  • 對於一些特定的事務,可以使用表鎖來提高處理速度或減少死鎖的可能

E. sqlserver怎麼實現一個行鎖

1如何鎖一個表的某一行


SELECT*FROMtableROWLOCKWHEREid=1

2鎖定資料庫的一個表

SELECT*FROMtableWITH(HOLDLOCK)

加鎖語句:
sybase:
update表setcol1=col1where1=0;
MSSQL:
selectcol1from表(tablockx)where1=0;
oracle:
LOCKTABLE表INEXCLUSIVEMODE;
加鎖後其它人不可操作,直到加鎖用戶解鎖,用commit或rollback解鎖

F. 「sql」加鎖機制是什麼

您好!鎖是資料庫中的一個非常重要的概念,它主要用於多用戶環境下保證資料庫完整性和一致性。
我們知道,多個用戶能夠同時操縱同一個資料庫中的數據,會發生數據不一致現象。即如果沒有鎖定且多個用戶同時訪問一個資料庫,則當他們的事務同時使用相同的數據時可能會發生問題。這些問題包括:丟失更新、臟讀、不可重復讀和幻覺讀。資料庫加鎖就是為了解決以上的問題。
當然,加鎖固然好,但是一定要避免死鎖的出現。
在資料庫系統中,死鎖是指多個用戶(進程)分別鎖定了一個資源,並又試圖請求鎖定對方已經鎖定的資源,這就產生了一個鎖定請求環,導致多個用戶(進程)都處於等待對方釋放所鎖定資源的狀態。這種死鎖是最典型的死鎖形式, 例如在同一時間內有兩個事務A和B,事務A有兩個操作:鎖定表part和請求訪問表supplier;事務B也有兩個操作:鎖定表supplier和請求訪問表part。結果,事務A和事務B之間發生了死鎖。死鎖的第二種情況是,當在一個資料庫中時,有若干個長時間運行的事務執行並行的操作,當查詢分析器處理一種非常復雜的查詢例如連接查詢時,那麼由於不能控制處理的順序,有可能發生死鎖現象。
在應用程序中就可以採用下面的一些方法來盡量避免死鎖了: (1)合理安排表訪問順序。 (2)在事務中盡量避免用戶干預,盡量使一個事務處理的任務少些, 保持事務簡短並在一個批處理中。 (3)數據訪問時域離散法, 數據訪問時域離散法是指在客戶機/伺服器結構中,採取各種控制手段控制對資料庫或資料庫中的對象訪問時間段。主要通過以下方式實現: 合理安排後台事務的執行時間,採用工作流對後台事務進行統一管理。工作流在管理任務時,一方面限制同一類任務的線程數(往往限制為1個),防止資源過多佔用; 另一方面合理安排不同任務執行時序、時間,盡量避免多個後台任務同時執行,另外, 避免在前台交易高峰時間運行後台任務。 (4)數據存儲空間離散法。數據存儲空間離散法是指採取各種手段,將邏輯上在一個表中的數據分散到若干離散的空間上去,以便改善對表的訪問性能。主要通過以下方法實現: 第一,將大表按行或列分解為若干小表; 第二,按不同的用戶群分解。 (5)使用盡可能低的隔離性級別。隔離性級別是指為保證資料庫數據的完整性和一致性而使多用戶事務隔離的程度,SQL92定義了4種隔離性級別:未提交讀、提交讀、可重復讀和可串列。如果選擇過高的隔離性級別,如可串列,雖然系統可以因實現更好隔離性而更大程度上保證數據的完整性和一致性,但各事務間沖突而死鎖的機會大大增加,大大影響了系統性能。 (6)使用綁定連接, 綁定連接允許兩個或多個事務連接共享事務和鎖,而且任何一個事務連接要申請鎖如同另外一個事務要申請鎖一樣,因此可以允許這些事務共享數據而不會有加鎖的沖突。
總之,了解SQL Server的鎖機制,掌握資料庫鎖定方法, 對一個合格的DBA來說是很重要的。

G. 如何在SQLServer中鎖定某行記錄

如何在SQLServer中鎖定某行記錄
SELECT au_lname FROM authors WITH (ROWLOCK )

鎖定提示 描述
HOLDLOCK 將共享鎖保留到事務完成,而不是在相應的表、行或數據頁不再需要時就立即釋放鎖。HOLDLOCK等同於SERIALIZABLE。
NOLOCK 不要發出共享鎖,並且不要提供排它鎖。當此選項生效時,可能會讀取未提交的事務或一組在讀取中間回滾的頁面。有可能發生臟讀。僅應用於 SELECT語句。
PAGLOCK 在通常使用單個表鎖的地方採用頁鎖。
READCOMMITTED 用與運行在提交讀隔離級別的事務相同的鎖語義執行掃描。默認情況下,SQLServer 2000 在此隔離級別上操作。
READPAST 跳過鎖定行。此選項導致事務跳過由其它事務鎖定的行(這些行平常會顯示在結果集內),而不是阻塞該事務,使其等待其它事務釋放在這些行上的鎖。READPAST 鎖提示僅適用於運行在提交讀隔離級別的事務,並且只在行級鎖之後讀取。僅適用於SELECT 語句。

H. SQL SERVER 中如何使用行鎖

給你個最詳細的吧 可能有你要的內容 鎖的概述 一. 為什麼要引入鎖 多個用戶同時對資料庫的並發操作時會帶來以下數據不一致的問題: 丟失更新 A,B兩個用戶讀同一數據並進行修改,其中一個用戶的修改結果破壞了另一個修改的結果,比如訂票系統 臟讀 A用戶修改了數據,隨後B用戶又讀出該數據,但A用戶因為某些原因取消了對數據的修改,數據恢復原值,此時B得到的數據就與資料庫內的數據產生了不一致 不可重復讀 A用戶讀取數據,隨後B用戶讀出該數據並修改,此時A用戶再讀取數據時發現前後兩次的值不一致 並發控制的主要方法是封鎖,鎖就是在一段時間內禁止用戶做某些操作以避免產生數據不一致 二 鎖的分類 鎖的類別有兩種分法: 1. 從資料庫系統的角度來看:分為獨占鎖(即排它鎖),共享鎖和更新鎖 MS-SQL Server 使用以下資源鎖模式。 鎖模式 描述 共享 (S) 用於不更改或不更新數據的操作(只讀操作),如 SELECT 語句。 更新 (U) 用於可更新的資源中。防止當多個會話在讀取、鎖定以及隨後可能進行的資源更新時發生常見形式的死鎖。 排它 (X) 用於數據修改操作,例如 INSERT、UPDATE 或 DELETE。確保不會同時同一資源進行多重更新。 意向鎖 用於建立鎖的層次結構。意向鎖的類型為:意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。 架構鎖 在執行依賴於表架構的操作時使用。架構鎖的類型為:架構修改 (Sch-M) 和架構穩定性 (Sch-S)。 大容量更新 (BU) 向表中大容量復制數據並指定了 TABLOCK 提示時使用。 共享鎖 共享 (S) 鎖允許並發事務讀取 (SELECT) 一個資源。資源上存在共享 (S) 鎖時,任何其它事務都不能修改數據。一旦已經讀取數據,便立即釋放資源上的共享 (S) 鎖,除非將事務隔離級別設置為可重復讀或更高級別,或者在事務生存周期內用鎖定提示保留共享 (S) 鎖。 更新鎖 更新 (U) 鎖可以防止通常形式的死鎖。一般更新模式由一個事務組成,此事務讀取記錄,獲取資源(頁或行)的共享 (S) 鎖,然後修改行,此操作要求鎖轉換為排它 (X) 鎖。如果兩個事務獲得了資源上的共享模式鎖,然後試圖同時更新數據,則一個事務嘗試將鎖轉換為排它 (X) 鎖。共享模式到排它鎖的轉換必須等待一段時間,因為一個事務的排它鎖與其它事務的共享模式鎖不兼容;發生鎖等待。第二個事務試圖獲取排它 (X) 鎖以進行更新。由於兩個事務都要轉換為排它 (X) 鎖,並且每個事務都等待另一個事務釋放共享模式鎖,因此發生死鎖。 若要避免這種潛在的死鎖問題,請使用更新 (U) 鎖。一次只有一個事務可以獲得資源的更新 (U) 鎖。如果事務修改資源,則更新 (U) 鎖轉換為排它 (X) 鎖。否則,鎖轉換為共享鎖。 排它鎖 排它 (X) 鎖可以防止並發事務對資源進行訪問。其它事務不能讀取或修改排它 (X) 鎖鎖定的數據。 意向鎖 意向鎖表示 SQL Server 需要在層次結構中的某些底層資源上獲取共享 (S) 鎖或排它 (X) 鎖。例如,放置在表級的共享意向鎖表示事務打算在表中的頁或行上放置共享 (S) 鎖。在表級設置意向鎖可防止另一個事務隨後在包含那一頁的表上獲取排它 (X) 鎖。意向鎖可以提高性能,因為 SQL Server 僅在表級檢查意向鎖來確定事務是否可以安全地獲取該表上的鎖。而無須檢查表中的每行或每頁上的鎖以確定事務是否可以鎖定整個表。 意向鎖包括意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。 鎖模式 描述 意向共享 (IS) 通過在各資源上放置 S 鎖,表明事務的意向是讀取層次結構中的部分(而不是全部)底層資源。 意向排它 (IX) 通過在各資源上放置 X 鎖,表明事務的意向是修改層次結構中的部分(而不是全部)底層資源。IX 是 IS 的超集。 與意向排它共享 (SIX) 通過在各資源上放置 IX 鎖,表明事務的意向是讀取層次結構中的全部底層資源並修改部分(而不是全部)底層資源。允許頂層資源上的並發 IS 鎖。例如,表的 SIX 鎖在表上放置一個 SIX 鎖(允許並發 IS 鎖),在當

I. sql 怎樣加行鎖

updatetable_namewith(rowlock)setcolumn_name=new_valuewhereyour_condition

J. MySQL簡單介紹——換個角度認識MySQL

1、InnoDB存儲引擎
Mysql版本>=5.5 默認的存儲引擎,MySQL推薦使用的存儲引擎。支持事務,行級鎖定,外鍵約束。事務安全型存儲引擎。更加註重數據的完整性和安全性。
存儲格式 : 數據,索引集中存儲,存儲於同一個表空間文件中。
InnoDB的行鎖模式及其加鎖方法: InnoDB中有以下兩種類型的行鎖:共享鎖(讀鎖: 允許事務對一條行數據進行讀取)和 互斥鎖(寫鎖: 允許事務對一條行數據進行刪除或更新), 對於update,insert,delete語句,InnoDB會自動給設計的數據集加互斥鎖,對於普通的select語句,InnoDB不會加任何鎖。
InnoDB行鎖的實現方式: InnoDB行鎖是通過給索引上的索引項加鎖來實現的,如果沒有索引,InnoDB將通過隱藏的聚簇索引來對記錄加鎖。InnoDB這種行鎖實現特點意味著:如果不通過索引條件檢索數據,那麼InnoDB將對表中的所有記錄加鎖,實際效果跟表鎖一樣。
(1)在不通過索引條件查詢時,InnoDB會鎖定表中的所有記錄。
(2)Mysql的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪問不同行的記錄,但是如果使用相同的索引鍵,是會出現沖突的。
(3)當表有多個索引的時候,不同的事務可以使用不同的索引鎖定不同的行,但都是通過行鎖來對數據加鎖。
優點:
1、支持事務處理、ACID事務特性;
2、實現了SQL標準的四種隔離級別( 原子性( Atomicity )、一致性( Consistency )、隔離性(Isolation )和持續性(Durability ));
3、支持行級鎖和外鍵約束;
4、可以利用事務日誌進行數據恢復。
5、鎖級別為行鎖,行鎖優點是適用於高並發的頻繁表修改,高並發是性能優於 MyISAM。缺點是系統消耗較大。
6、索引不僅緩存自身,也緩存數據,相比 MyISAM 需要更大的內存。
缺點:
因為它沒有保存表的行數,當使用COUNT統計時會掃描全表。

使用場景:
(1)可靠性要求比較高,或者要求事務;(2)表更新和查詢都相當的頻繁,並且表鎖定的機會比較大的情況。
2、 MyISAM存儲引擎
MySQL<= 5.5 MySQL默認的存儲引擎。ISAM:Indexed Sequential Access Method(索引順序存取方法)的縮寫,是一種文件系統。擅長與處理,高速讀與寫。
功能:
(1)支持數據壓縮存儲,但壓縮後的表變成了只讀表,不可寫;如果需要更新數據,則需要先解壓後更新。
(2)支持表級鎖定,不支持高並發;
(3)支持並發插入。寫操作中的插入操作,不會阻塞讀操作(其他操作);
優點:
1.高性能讀取;
2.因為它保存了表的行數,當使用COUNT統計時不會掃描全表;
缺點:
1、鎖級別為表鎖,表鎖優點是開銷小,加鎖快;缺點是鎖粒度大,發生鎖沖動概率較高,容納並發能力低,這個引擎適合查詢為主的業務。
2、此引擎不支持事務,也不支持外鍵。
3、INSERT和UPDATE操作需要鎖定整個表;
使用場景:
(1)做很多count 的計算;(2)插入不頻繁,查詢非常頻繁;(3)沒有事務。
InnoDB和MyISAM一些細節上的差別:
1、InnoDB不支持FULLTEXT類型的索引,MySQL5.6之後已經支持(實驗性)。
2、InnoDB中不保存表的 具體行數,也就是說,執行select count() from table時,InnoDB要掃描一遍整個表來計算有多少行,但是MyISAM只要簡單的讀出保存好的行數即可。注意的是,當count()語句包含 where條件時,兩種表的操作是一樣的。
3、對於AUTO_INCREMENT類型的欄位,InnoDB中必須包含只有該欄位的索引,但是在MyISAM表中,可以和其他欄位一起建立聯合索引。
4、DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除。
5、LOAD TABLE FROM MASTER操作對InnoDB是不起作用的,解決方法是首先把InnoDB表改成MyISAM表,導入數據後再改成InnoDB表,但是對於使用的額外的InnoDB特性(例如外鍵)的表不適用。
6、另外,InnoDB表的行鎖也不是絕對的,如果在執行一個SQL語句時MySQL不能確定要掃描的范圍,InnoDB表同樣會鎖全表。

1.索引概述
利用關鍵字,就是記錄的部分數據(某個欄位,某些欄位,某個欄位的一部分),建立與記錄位置的對應關系,就是索引。索引的關鍵字一定是排序的。索引本質上是表欄位的有序子集,它是提高查詢速度最有效的方法。一個沒有建立任何索引的表,就相當於一本沒有目錄的書,在每次查詢時就會進行全表掃描,這樣會導致查詢效率極低、速度也極慢。如果建立索引,那麼就好比一本添加的目錄,通過目錄的指引,迅速翻閱到指定的章節,提升的查詢性能,節約了查詢資源。
2.索引種類
從索引的定義方式和用途中來看:主鍵索引,唯一索引,普通索引,全文索引。
無論任何類型,都是通過建立關鍵字與位置的對應關系來實現的。索引是通過關鍵字找對應的記錄的地址。
以上類型的差異:對索引關鍵字的要求不同。
關鍵字:記錄的部分數據(某個欄位,某些欄位,某個欄位的一部分)。
普通索引,index:對關鍵字沒有要求。
唯一索引,unique index:要求關鍵字不能重復。同時增加唯一約束。
主鍵索引,primary key:要求關鍵字不能重復,也不能為NULL。同時增加主鍵約束。
全文索引,fulltext key:關鍵字的來源不是所有欄位的數據,而是從欄位中提取的特別關鍵詞。
PS:這里主鍵索引和唯一索引的區別在於:主鍵索引不能為空值,唯一索引允許空值;主鍵索引在一張表內只能創建一個,唯一索引可以創建多個。主鍵索引肯定是唯一索引,但唯一索引不一定是主鍵索引。
3.索引原則
如果索引不遵循使用原則,則可能導致索引無效。
(1)列獨立
如果需要某個欄位上使用索引,則需要在欄位參與的表達中,保證欄位獨立在一側。否則索引不會用到索引, 例如這條sql就不會用到索引:select * from A where id+1=10;
(2)左原則
Like:匹配模式必須要左邊確定不能以通配符開頭。例如:select * from A where name like '%小明%' ,不會用到索引,而select * from A where name like '小明%' 就可以用到索引(name欄位有建立索引),如果業務上需要用到'%小明%'這種方式,有兩種方法:1.可以考慮全文索引,但mysql的全文索引不支持中文;2.只查詢索引列或主鍵列,例如:select name from A where name like '%小明%' 或 select id from A where name like '%小明%' 或 select id,name from A where name like '%小明%' 這三種情況都會用到name的索引;
復合索引:一個索引關聯多個欄位,僅僅針對左邊欄位有效果,添加復合索引時,第一個欄位很重要,只有包含第一個欄位作為查詢條件的情況才會使用復合索引(必須用到建索引時選擇的第一個欄位作為查詢條件,其他欄位的順序無關),而且查詢條件只能出現and拼接,不能用or,否則則無法使用索引.
(3)OR的使用
必須要保證 OR 兩端的條件都存在可以用的索引,該查詢才可以使用索引。
(4)MySQL智能選擇
即使滿足了上面說原則,MySQL也能棄用索引,例如:select * from A where id > 1;這里棄用索引的主要原因:查詢即使使用索引,會導致出現大量的隨機IO,相對於從數據記錄的第一條遍歷到最後一條的順序IO開銷,還要大。
4.索引的使用場景
(1)索引檢索:檢索數據時使用索引。
(2)索引排序: 如果order by 排序需要的欄位上存在索引,則可能使用到索引。
(3)索引覆蓋: 索引擁有的關鍵字內容,覆蓋了查詢所需要的全部數據,此時,就不需要在數據區獲取數據,僅僅在索引區即可。覆蓋就是直接在索引區獲取內容,而不需要在數據區獲取。例如: select name from A where name like '小明%';
建立索引索引時,不能僅僅考慮where檢索,同時考慮其他的使用場景。(在所有的where欄位上增加索引,就是不合理的)
5.前綴索引
前綴索引是建立索引關鍵字一種方案。通常會使用欄位的整體作為索引關鍵字。有時,即使使用欄位前部分數據,也可以去識別某些記錄。就比如一個班級里,我要找王xx,假如姓王的只有1個人,那麼就可以建一個關鍵字為'王'的前綴索引。語法:Index `index_name` (`index_field`(N))使用index_name前N個字元建立的索引。
6.索引失效
(1) 應盡量避免在 where 子句中使用 != 或 > 操作符,否則將引擎放棄使用索引而進行全表掃描;
(2) 應盡量避免在 where 子句中使用 or 來連接條件,如果一個欄位有索引,一個欄位沒有索引,將導致引擎放棄使用索引而進行全表掃描;
(3) 應盡量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描;
(4)應盡量避免在 where 子句中對欄位進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描;如select id from t where num/2 = 100;
(5) 應盡量避免在where子句中對欄位進行函數操作,這將導致引擎放棄使用索引而進行全表掃描;如:select id from t where substring(name,1,3) = 』abc』 ;
(6)應盡量避免在where子句中對欄位進行類型轉換,這將導致引擎放棄使用索引而進行全表掃描; 如果列類型是字元串,那一定要在條件中將數據使用引號引用起來,如select id from t where id = 1;如果id欄位在表設計中是varchar類型,那麼即使id列上存的是數字,在查詢時也一定要用varchar去匹配,sql應改為select id from t where id = '1';
(7)應盡量避免在where子句中單獨引用復合索引里非第一位置的索引;

join 的兩種演算法:BNL 和 NLJ
NLJ(Nested Loop Join)嵌套循環演算法;以如下 SQL 為例:
select * from t1 join t2 on t1.a=t2.a
SQL 執行時內部流程是這樣的:
1. 先從 t1(假設這里 t1 被選為驅動表)中取出一行數據 X;
2. 從 X 中取出關聯欄位 a 值,去 t2 中進行查找,滿足條件的行取出;
3. 重復1、2步驟,直到表 t1 最後一行循環結束。
這就是一個嵌套循環的過程,如果在被驅動表上查找數據時可以使用索引,總的對比計算次數等於驅動表滿足 where 條件的行數。假設這里 t1、t2都是1萬行,則只需要 1萬次計算,這里用到的是Index Nested-Loops Join(INLJ,基於索引的嵌套循環聯接)。
如果 t1、t2 的 a 欄位都沒有索引,還按照上述的嵌套循環流程查找數據呢?每次在被驅動表上查找數據時都是一次全表掃描,要做1萬次全表掃描,掃描行數等於 1萬+1萬*1萬,這個效率很低,如果錶行數更多,掃描行數動輒幾百億,所以優化器肯定不會使用這樣的演算法,而是選擇 BNL 演算法;
BNLJ(Block Nested Loop Join)塊嵌套循環演算法;
1. 把 t1 表(假設這里 t1 被選為驅動表)滿足條件的數據全部取出放到線程的 join buffer 中;
2. 每次取 t2 表一行數據,去 joinbuffer 中進行查找,滿足條件的行取出,直到表 t2 最後一行循環結束。
這個演算法下,執行計劃的 Extra 中會出現 Using join buffer(Block Nested Loop),t1、t2 都做了一次全表掃描,總的掃描行數等於 1萬+1萬。但是由於 joinbuffer 維護的是一個無序數組,每次在 joinbuffer 中查找都要遍歷所有行,總的內存計算次數等於1萬*1萬。另外如果 joinbuffer 不夠大放不下驅動表的數據,則要分多次執行上面的流程,會導致被驅動表也做多次全表掃描。

BNLJ相對於NLJ的優點在於,驅動層可以先將部分數據載入進buffer,這種方法的直接影響就是將大大減少內層循環的次數,提高join的效率。
例如:
如果內層循環有100條記錄,外層循環也有100條記錄,這樣的話,每次外層循環先將10條記錄放到buffer中,內層循環的100條記錄每條與這個buffer中的10條記錄進行匹配,只需要匹配內層循環總記錄數次即可結束一次循環(在這里,即只需要匹配100次即可結束),然後將匹配成功的記錄連接後放入結果集中,接著,外層循環繼續向buffer中放入10條記錄,同理進行匹配,並將成功的記錄連接後放入結果集。後續循環以此類推,直到循環結束,將結果集發給client為止。
可以發現,若用NLJ,則需要100 * 100次才可結束,BNLJ則需要100 / block_size * 100 = 10 * 100次就可結束,大大減少了循環次數。

JOIN 按照功能大致分為如下三類:
JOIN、STRAIGHT_JOIN、INNER JOIN(內連接,或等值連接):取得兩個表中存在連接匹配關系的記錄。
LEFT JOIN(左連接):取得左表(table1)完全記錄,即是右表(table2)並無對應匹配記錄。
RIGHT JOIN(右連接):與 LEFT JOIN 相反,取得右表(table2)完全記錄,即是左表(table1)並無匹配對應記錄。
注意:mysql不支持Full join,不過可以通過UNION 關鍵字來合並 LEFT JOIN 與 RIGHT JOIN來模擬FULL join。
mysql 多表連接查詢方式,因為mysql只支持NLJ演算法,所以如果是小表驅動大表則效率更高;反之則效率下降;因此mysql對內連接或等值連接的方式做了一個優化,會去判斷join表的數據行大小,然後取數據行小的表為驅動表。
INNER JOIN、JOIN、WHERE等值連接和STRAIGHT_JOIN都能表示內連接,那平時如何選擇呢?一般情況下用INNER JOIN、JOIN或者WHERE等值連接,因為MySQL 會按照"小表驅動大表的策略"進行優化。當出現需要排序時,才考慮用STRAIGHT_JOIN指定某張表為驅動表。

兩表JOIN優化
a.當無order by條件時,根據實際情況,使用left/right/inner join即可,根據explain優化 ;
b.當有order by條件時,如select * from a inner join b where 1=1 and other condition order by a.col;使用explain解釋語句;
1)如果第一行的驅動表為a,則效率會非常高,無需優化;
2)否則,因為只能對驅動表欄位直接排序的緣故,會出現using temporary,所以此時需要使用STRAIGHT_JOIN明確a為驅動表,來達到使用a.col上index的優化目的;或者使用left join且Where條件中不含b的過濾條件,此時的結果集為a的全集,而STRAIGHT_JOIN為inner join且使用a作為驅動表。註:使用STRAIGHT_JOIN雖然不會using temporary,但也不是一定就能提高效率,如果a表數據遠遠超過b表,那麼有可能使用STRAIGHT_JOIN時比原來的sql效率更低,所以怎麼使用STRAIGHT_JOIN,還是要視情況而定。

在使用left join(或right join)時,應該清楚的知道以下幾點:
(1). on與 where的執行順序
ON 條件(「A LEFT JOIN B ON 條件表達式」中的ON)用來決定如何從 B 表中檢索數據行。如果 B 表中沒有任何一行數據匹配 ON 的條件,將會額外生成一行所有列為 NULL 的數據,在匹配階段 WHERE 子句的條件都不會被使用。僅在匹配階段完成以後,WHERE 子句條件才會被使用。它將從匹配階段產生的數據中檢索過濾。
所以我們要注意:在使用Left (right) join的時候,一定要在先給出盡可能多的匹配滿足條件,減少Where的執行。
(2).注意ON 子句和 WHERE 子句的不同
即使右表的數據不滿足ON後面的條件,也會在結果集拼接一條為NULL的數據行,但WHERE後面的條件不一樣,右表不滿足WHERE的條件,左表關聯的數據也會被過濾掉。
(3).盡量避免子查詢,而用join
往往性能這玩意兒,更多時候體現在數據量比較大的時候,此時,我們應該避免復雜的子查詢。

(1)in 和 not in 要慎用,如:select id from t where num in(1,2,3)對於連續的數值,能用 between 就不要用 in:select id from t where num between 1 and 3很多時候用 exists 代替 in 是一個好的選擇:select num from a where num in(select num from b)用下面的語句替換:select num from a where exists(select 1 from b where num=a.num)
(2)Update 語句,如果只更改1、2個欄位,不要Update全部欄位,否則頻繁調用會引起明顯的性能消耗,同時帶來大量日誌。
(3)join語句,MySQL裡面的join是用小表去驅動大表,而由於MySQL join實現的原理就是做循環,比如left join就是對左邊的數據進行循環去驅動右邊的表,左邊有m條記錄匹配,右邊有n條記錄那麼就是做m次循環,每次掃描n行數據,總掃面行數是m*n行數據。左邊返回的結果集的大小就決定了循環的次數,故單純的用小表去驅動大表不一定的正確的,小表的結果集可能也大於大表的結果集,所以寫join的時候盡可能的先估計兩張表的可能結果集,用小結果集去驅動大結果集.值得注意的是在使用left/right join的時候,從表的條件應寫在on之後,主表應寫在where之後.否則MySQL會當作普通的連表查詢;
(4)select count(*) from table;這樣不帶任何條件的count會引起全表掃描,並且沒有任何業務意義,是一定要杜絕的;
(5)select * from t 這種語句要盡量避免,使用具體的欄位代替*,更有實際意義,需要什麼欄位就返回什麼欄位;
(6)數據量大的情況下,limit要慎用,因為使用limit m,n方式分頁時,mysql每次都是查詢前m+n條,然後舍棄前m條,所以m越大,偏移量越大,性能就越差。比如:select * from A limit 1000000,20這鍾,查詢效率就會非常低,當分頁的頁數大於一定的數量之後,就可以換種方式來分頁:select * from A a join (select id from A limit 1000000,20) b on a.id=b.id;