有唯一/主鍵(primary或者unique)存在時,避免重複插入的方法
在一些報名/拉票類型活動中, 往往需要對uin做唯一鍵處理,限制1個使用者隻能有1條報名記錄。 為避免并發時重複資料的插入,
常用方法有3種:
insert ignore into
replace into
on duplicate key update
假設有表如下:

基本文法:
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插入資料。一句話概括就是:“無則添加,有則忽略”。
假設原資料庫已有資料:
執行insert ignore重複插入,提示插入了0行(表示忽略此次操作):
執行insert ignore插入,無主鍵重複,則正常插入新行:
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,則一般是表中有多個唯一索引,有可能是一個單一行替換了多個舊行。
執行上述replace語句後, 有uin主鍵重複,則先删除原有重複記錄,再執行新插入,影響行數2行:
執行replace(無主鍵沖突),則是插入新行,影響行數1:
特殊說明:
如果表中有一個自增主鍵,則不建議用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适用的場景比較特定:就是當資料入庫時,若遇到主鍵/唯一鍵重複存在的資料時,則需要去修改它;不存在時則新增。
執行Insert....on duplicate key update 有主鍵重複時,在原來語句上執行update,影響行數2行:
在使用上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字段,無重複存在的記錄則正常插入。
上述語句執行後,結果如下:
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>的效率來說實際是相差不大的,如下圖:
這和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的妙用