天天看點

Web 開發 MYSQL 常用方法整理 (上)

有唯一/主鍵(primary或者unique)存在時,避免重複插入的方法

在一些報名/拉票類型活動中, 往往需要對uin做唯一鍵處理,限制1個使用者隻能有1條報名記錄。 為避免并發時重複資料的插入,

常用方法有3種:

insert ignore into

replace into

on duplicate key update

假設有表如下:

Web 開發 MYSQL 常用方法整理 (上)

基本文法:

Insert ignore into<code>tbMyTest</code> (<code>uin</code>, <code>num</code>, <code>dttime</code>) values(516751917, 1, now());

分析:

Insert ignore的好處是,當存在唯一/主鍵沖突時,則直接忽略最新的insert操作,mysql傳回0不報錯;沒有沖突則正常insert插入資料。一句話概括就是:“無則添加,有則忽略”。

假設原資料庫已有資料:

Web 開發 MYSQL 常用方法整理 (上)

執行insert ignore重複插入,提示插入了0行(表示忽略此次操作):

Web 開發 MYSQL 常用方法整理 (上)

執行insert ignore插入,無主鍵重複,則正常插入新行:

Web 開發 MYSQL 常用方法整理 (上)

Replace into,也是可以用于避免資料重複插入的方法,但它與insert ignore最大的不同就是: 當有唯一/主鍵沖突時,insert ignore是直接忽略新資料,而releace into 是用新資料整行替換舊資料, 它會先從資料表中删除唯一/主鍵沖突的行,再嘗試插入新行。

Replace into <code>tbMyTest</code> (<code>uin</code>, <code>num</code>, <code>dttime</code>) values(516751917, 2, now());

關于傳回:

Replace into執行後會傳回受影響的行數,該數是被删除和被插入的行數總和。如果傳回數是1,則說明是首次插入資料; 若傳回數是2,則說明在新行插入前,有一行舊資料被删除;若是傳回數大于2,則一般是表中有多個唯一索引,有可能是一個單一行替換了多個舊行。

Web 開發 MYSQL 常用方法整理 (上)

執行上述replace語句後, 有uin主鍵重複,則先删除原有重複記錄,再執行新插入,影響行數2行:

Web 開發 MYSQL 常用方法整理 (上)

執行replace(無主鍵沖突),則是插入新行,影響行數1:

Web 開發 MYSQL 常用方法整理 (上)

特殊說明:

如果表中有一個自增主鍵,則不建議用replace into,因為replace後新舊記錄的主鍵值不同,若是還有其他表中與本表主鍵有關聯資料的話,關聯關系就會被破壞。再者,頻繁的replace into,自增值迅速變大,會有溢出風險。

常用文法:

Insert into <code>tbMyTest</code> (<code>uin</code>, <code>num</code>, <code>dttime</code>) values(516751917, 5, now()) on duplicate key update <code>num</code>=<code>num</code>+1,<code>dttime</code>=now();

文法解析:

當在insert時若遇到主鍵/唯一鍵沖突,則會在原語句上執行update後面的操作, 無重複時則正常insert插入。

On deplicate key update适用的場景比較特定:就是當資料入庫時,若遇到主鍵/唯一鍵重複存在的資料時,則需要去修改它;不存在時則新增。

Web 開發 MYSQL 常用方法整理 (上)

執行Insert....on duplicate key update 有主鍵重複時,在原來語句上執行update,影響行數2行:

Web 開發 MYSQL 常用方法整理 (上)

在使用上on duplicate key update 也可以支援多行插入,多行插入時,可以使用VALUES(列名)函數引用列值進行更新操作。

方法如下:

Insert into <code>tbMyTest</code> (<code>uin</code>, <code>num</code>, <code>dttime</code>) values(<code>516751917</code>, <code>8</code>, now()),(<code>21568475</code>, <code>2</code>, now()) on duplicate key update <code>num</code>=VALUES(<code>num</code>);

以上語句意思就是說:插入資料時,若目前行存在唯一鍵沖突,則引用目前行insert時的num列來更新num字段,無重複存在的記錄則正常插入。

Web 開發 MYSQL 常用方法整理 (上)

上述語句執行後,結果如下:

Web 開發 MYSQL 常用方法整理 (上)

uin為111111遇到主鍵重複,是以是在原語句上update的,将num值update為目前語句的VALUES('num'),也就是num=8,影響行數是2行。 而uin為333333的行沒有主鍵重複,是以是新增插入, 影響行數是1行。 故,總影響行數是3行。

基于MYSQL select資料取值原理,如果抛開索引和where,光從<code>select *</code>和<code>select a b c</code>的效率來說實際是相差不大的,如下圖:

Web 開發 MYSQL 常用方法整理 (上)

這和mysql内部資料存儲結構有關,詳細原因有興趣的可以參考mysql的資料查找原理。這裡呢就重點說說,兩者在程式設計習慣上和擴充性上的差别:

(1)不管是<code>select *</code> 還是 <code>select a b c</code>,查詢效率重點還是取決于where後面的索引設計

(2)原則上,盡量少用<code>elect *</code>

雖然從擴充性而已,如果表結構變更比較頻繁,使用<code>select *</code>會減少不少的代碼變更,但是在營銷活動開發的應用場景上說, 每個活動都是短期存在的,且表結構變化不大,每條sql語句讀取的字段都比較明确,建議優先使用<code>select a b c</code>。

<code>select a b c</code> 可以減少網絡傳輸,減少伺服器的開銷。

2、<code>select count(1)</code> 、<code>count(*)</code>、count(列名)的差別

整理中。。。

3、關于limit的妙用