MySQL開(kāi)發(fā)規(guī)范
為海湖新等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及海湖新網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、海湖新網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
文件狀態(tài):
[ ] 草稿
[√] 正式發(fā)布
[ ] 正在修改 文件標(biāo)識(shí):
當(dāng)前版本: V1.0
作 者: 賀磊
完成日期: 2016-05-24
變更記錄
序號(hào) 修改日期 修改內(nèi)容 修改人 審核人 批準(zhǔn)人 批準(zhǔn)日期
1 2016-05-24 MySQL開(kāi)發(fā)規(guī)范 賀磊
MySQL開(kāi)發(fā)規(guī)范
1. 簡(jiǎn)介
持續(xù)借鑒、收集并整理一些開(kāi)發(fā)規(guī)范和技巧,期望能更充分利用MySQL的特性,得到更好的性能。
規(guī)范是死的,人是活的。
現(xiàn)在定義的規(guī)范,是為以后推翻準(zhǔn)備的。
1.1 目的
提供給開(kāi)發(fā)人員參考,方便寫成更有效率的開(kāi)發(fā)。
1.2 范圍
文檔涉及的范圍:需要基于MySQL做應(yīng)用開(kāi)發(fā)的人員。
1.3 定義、首字母縮寫詞和縮略語(yǔ)
暫無(wú)
2. 數(shù)據(jù)庫(kù)設(shè)計(jì)
目標(biāo)三個(gè):功能實(shí)現(xiàn),可伸縮性,可用性。
關(guān)鍵點(diǎn):平衡業(yè)務(wù)技術(shù)各個(gè)方面,做好取舍。
80%的性能優(yōu)化來(lái)自架構(gòu)設(shè)計(jì)的優(yōu)化。
2.1 引擎及版本選擇
******引擎建議使用InnoDB
根據(jù)目前我們業(yè)務(wù)的特點(diǎn),建議使用MySQL5.6社區(qū)版。
2.2 架構(gòu)淺談
開(kāi)發(fā)大牛都擅長(zhǎng),這里不多提,僅標(biāo)注一下。
2.2.1 讀寫分離
2.2.2 分庫(kù)分表
3. 表設(shè)計(jì)
先看一個(gè)范例:
create table erp_example( id int(10) unsigned NOT NULL AUTO_INCREMENT,/**每個(gè)表都要有主鍵id, int無(wú)符號(hào)自增,且與業(yè)務(wù)無(wú)關(guān)。**/ server_type TINYINT(3) UNSIGNED NOT NULL DEFAULT 0,/**如果存儲(chǔ)類型,例如1:北京,2:上海,3:廣州,若無(wú)負(fù)數(shù)則用unsigned可以提高范圍。若無(wú)需字母,不要用char(1)來(lái)存**/ name varchar(5) NOT NULL DEFAULT '',/**varchar,char根據(jù)實(shí)際需要賦值,越小越好,且能用NOT NULL DEFAULT ''就用,NULL不但占據(jù)空間,且會(huì)降低索引效率,用''空字符串代替。**/ PRIMARY KEY(id), KEY `idx_name` (`name`)/**索引用idx_列名來(lái)標(biāo)記,唯一索引用uniq_列名來(lái)標(biāo)記**/ ) ENGINE=innodb AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
3.1 設(shè)計(jì)規(guī)范
3.1.1 每張表都要有主鍵id int(10) UNSIGNED ,且與業(yè)務(wù)無(wú)關(guān)。 NOT NULL AUTO_INCREMENT 。
3.1.2 建議字段定義為NOT NULL,需為空字段可定義為NOT NULL DEFAULT ''或0(0不要賦予實(shí)際意義)。
3.1.3 庫(kù)名、表名、字段名必須使用小寫字母,“_”分割。
3.1.4 庫(kù)名、表名、字段名不超過(guò)12個(gè)字符。
3.1.5 庫(kù)名、表名、字段名見(jiàn)名知意,建議使用名詞而不是動(dòng)詞。
3.1.6 存儲(chǔ)精確浮點(diǎn)數(shù)必須使用DECIMAL替代FLOAT和DOUBLE。
3.1.7 建議使用UNSIGNED存儲(chǔ)非負(fù)數(shù)值。
3.1.8 建議使用INT UNSIGNED存儲(chǔ)IPV4。
3.1.9 ×××定義中建議采用INT(10),而不是INT(1),INT(11)或其他。
3.1.10 存儲(chǔ)狀態(tài),性別等,用TINYINT,如果不需要負(fù)數(shù)加UNSIGNED。使用TINYINT UNSIGNED。
3.1.11 不建議使用ENUM類型,使用TINYINT來(lái)代替。
3.1.12 盡可能不使用TEXT、BLOB類型。
3.1.13 VARCHAR(N),N表示的是字符數(shù)不是字節(jié)數(shù),比如VARCHAR(255),可以最大可存儲(chǔ)255個(gè)漢字,需要根據(jù)實(shí)際的寬度來(lái)選擇N。VARCHAR(N),N盡可能小,因?yàn)镸ySQL一個(gè)表中所有的VARCHAR字段最大長(zhǎng)度是65535個(gè)字節(jié)21845個(gè)漢字,進(jìn)行排序和創(chuàng)建臨時(shí)表一類的內(nèi)存操作時(shí),會(huì)使用N的長(zhǎng)度申請(qǐng)內(nèi)存。
3.1.14 表字符集選擇UTF8。
3.1.15 存儲(chǔ)年使用YEAR類型。
3.1.16 存儲(chǔ)日期使用DATE類型。
3.1.17 存儲(chǔ)時(shí)間(精確到秒)建議使用TIMESTAMP類型,因?yàn)門IMESTAMP使用4字節(jié),DATETIME使用8個(gè)字節(jié)。TIMESTAMP類型保存的值不能比1970早或比2037晚。
3.1.18 將過(guò)大字段拆分到其他表中。
3.1.19 禁止在數(shù)據(jù)庫(kù)中使用VARBINARY、BLOB存儲(chǔ)圖片、文件等。
3.1.20 表結(jié)構(gòu)變更需要通知DBA審核。
一句話總結(jié):能NOT NULL 就NOT NULL,char、varchar用NOT NULL DEFAULT '',tinyint、smallint、int用NOT NULL DEFAULT 0。char、varchar取值要吝嗇,根據(jù)實(shí)際需求給,比如人名一般不超過(guò)5個(gè),varchar(5),不要varchar(200)。int、tinyint這類,int(1)和int(13)都是一樣的,我們統(tǒng)一用int(10),tinyint取值范圍[-128,127],加了unsigned取值[0,255],如果不需要存儲(chǔ)負(fù)數(shù),整型類型的加unsigned。
3.2 索引
3.2.1 非唯一索引必須按照“idx_字段名稱_字段名稱[_字段名]”進(jìn)行命名。
3.2.2 唯一索引必須按照“uniq_字段名稱_字段名稱[_字段名]”進(jìn)行命名。
3.2.3 索引名稱必須使用小寫。
3.2.4 索引中的字段數(shù)建議不超過(guò)5個(gè)。
3.2.5 單張表的索引數(shù)量控制在5個(gè)以內(nèi)。
3.2.6 索引字段的順序需要考慮字段值去重之后的個(gè)數(shù),個(gè)數(shù)多的放在前面。
3.2.7 使用EXPLAIN判斷SQL語(yǔ)句是否合理使用索引,盡量避免extra列出現(xiàn):Using File Sort,UsingTemporary。
3.2.8 UPDATE、DELETE語(yǔ)句需要根據(jù)WHERE條件添加索引。
3.2.9 不建議使用%前綴模糊查詢,例如LIKE “%weibo”。
3.2.10 合理創(chuàng)建聯(lián)合索引(避免冗余),(a,b,c) 相當(dāng)于 (a) 、(a,b) 、(a,b,c),但(a,c)只能用到部分索引。
3.2.11 合理利用覆蓋索引。
3.2.12 SQL變更需要確認(rèn)索引是否需要變更并通知DBA。
3.3 SQL語(yǔ)句
3.3.1 SQL語(yǔ)句中IN包含的值不應(yīng)過(guò)多。
3.3.2 UPDATE、DELETE語(yǔ)句不使用LIMIT。
3.3.3 WHERE條件中必須使用合適的類型,避免MySQL進(jìn)行隱式類型轉(zhuǎn)化。
3.3.4 SELECT語(yǔ)句只獲取需要的字段。
3.3.5 SELECT、INSERT語(yǔ)句必須顯式的指明字段名稱,不使用SELECT *,不使用INSERT INTO table()。
3.3.6 使用SELECT column_name1, column_name2 FROM table WHERE[condition]而不是SELECT column_name1 FROM table WHERE[condition]和SELECT column_name2 FROM table WHERE [condition]。
3.3.7 WHERE條件中的非等值條件(IN、BETWEEN、<、<=、>、>=)會(huì)導(dǎo)致后面的條件使用不了索引。
3.3.8 避免在SQL語(yǔ)句進(jìn)行數(shù)學(xué)運(yùn)算或者函數(shù)運(yùn)算,容易將業(yè)務(wù)邏輯和DB耦合在一起。
3.3.9 INSERT語(yǔ)句使用batch提交(INSERT INTO table VALUES(),(),()……),values的個(gè)數(shù)不應(yīng)過(guò)多。
3.3.10 避免使用存儲(chǔ)過(guò)程、觸發(fā)器、函數(shù)等,容易將業(yè)務(wù)邏輯和DB耦合在一起,并且MySQL的存儲(chǔ)過(guò)程、觸發(fā)器、函數(shù)中存在一定的bug。
3.3.11 避免使用JOIN。
3.3.12 使用合理的SQL語(yǔ)句減少與數(shù)據(jù)庫(kù)的交互次數(shù)。
3.3.13 不使用ORDER BY RAND(),使用其他方法替換。
3.3.14 建議使用合理的分頁(yè)方式以提高分頁(yè)的效率。
3.3.15 統(tǒng)計(jì)表中記錄數(shù)時(shí)使用COUNT(*),而不是COUNT(primary_key)和COUNT(1)。
3.4 分表
3.4.1 每張表數(shù)據(jù)量建議控制在500w以下。
3.4.2 使用時(shí)間分表,表名后綴必須使用特定格式,比如按年分表user_2016按月分表user_201602、按日分表user_20160209。
4. FAQ
4.1 庫(kù)名、表名、字段名使用小寫字母,“_”分割。
a)MySQL有配置參數(shù)lower_case_table_names,不可動(dòng)態(tài)更改,linux系統(tǒng)默認(rèn)為0,即庫(kù)表名以實(shí)際情況存儲(chǔ),大小寫敏感。如果是1,以小寫存儲(chǔ),大小寫不敏感。如果是2,以實(shí)際情況存儲(chǔ),但以小寫比較。
b) 如果大小寫混合用,可能存在abc,Abc,ABC等多個(gè)表共存,容易導(dǎo)致混亂。
c) 字段名顯示區(qū)分大小寫,但實(shí)際使用不區(qū)分,即不可以建立兩個(gè)名字一樣但大小寫不一樣的字段。
d) 為了統(tǒng)一規(guī)范, 庫(kù)名、表名、字段名使用小寫字母。
4.2 庫(kù)名、表名、字段名必須不超過(guò)12個(gè)字符。
庫(kù)名、表名、字段名支持最多64個(gè)字符,但為了統(tǒng)一規(guī)范、易于辨識(shí)以及減少傳輸量,必須不超過(guò)12字符。
4.3 庫(kù)名、表名、字段名見(jiàn)名知意,建議使用名詞而不是動(dòng)詞。
a) 用戶評(píng)論可用表名usercomment或者comment。
b) 庫(kù)表是一種客觀存在的事物,一種對(duì)象,所以建議使用名詞。
4.4 建議使用InnoDB存儲(chǔ)引擎。
a) 5.5以后的默認(rèn)引擘,支持事務(wù),行級(jí)鎖,更好的恢復(fù)性,高并發(fā)下性能更好,對(duì)多核,大內(nèi)存,ssd等硬件支持更好。
b) 具體比較可見(jiàn)附件的官方白皮書。
4.5 存儲(chǔ)精確浮點(diǎn)數(shù)必須使用DECIMAL替代FLOAT和DOUBLE。
a) mysql中的數(shù)值類型(不包括整型):
IEEE754浮點(diǎn)數(shù):float? (單精度) , double? 或real? (雙精度)
定點(diǎn)數(shù): decimal或 numeric
單精度浮點(diǎn)數(shù)的有效數(shù)字二進(jìn)制是24位,按十進(jìn)制來(lái)說(shuō),是8位;雙精度浮點(diǎn)數(shù)的有效數(shù)字二進(jìn)制是53位,按十進(jìn)制來(lái)說(shuō),是16 位
一個(gè)實(shí)數(shù)的有效數(shù)字超過(guò)8位,用單精度浮點(diǎn)數(shù)來(lái)表示的話,就會(huì)產(chǎn)生誤差!同樣,如果一個(gè)實(shí)數(shù)的有效數(shù)字超過(guò)16位,用雙精度浮點(diǎn)數(shù)來(lái)表示,也會(huì)產(chǎn)生誤差
b)IEEE754標(biāo)準(zhǔn)的計(jì)算機(jī)浮點(diǎn)數(shù),在內(nèi)部是用二進(jìn)制表示的,但在將一個(gè)十進(jìn)制數(shù)轉(zhuǎn)換為二進(jìn)制浮點(diǎn)數(shù)時(shí),也會(huì)造成誤差,原因是不是所有的數(shù)都能轉(zhuǎn)換成有限長(zhǎng)度的二進(jìn)制數(shù)。
即一個(gè)二進(jìn)制可以準(zhǔn)確轉(zhuǎn)換成十進(jìn)制,但一個(gè)帶小數(shù)的十進(jìn)制不一定能夠準(zhǔn)確地用二進(jìn)制來(lái)表示。
實(shí)例:
drop table if exists t;
create table t(value float(10,2));
insert into t values(131072.67),(131072.68);
select value from t;
+-----------+
|value|
+-----------+
| 131072.67 |
| 131072.69 |
+-----------+
4.6 建議使用UNSIGNED存儲(chǔ)非負(fù)數(shù)值。
同樣的字節(jié)數(shù),存儲(chǔ)的數(shù)值范圍更大。如tinyint 有符號(hào)為 -128-127,無(wú)符號(hào)為0-255
4.7 如何使用INT UNSIGNED存儲(chǔ)ip?
使用INTUNSIGNED而不是char(15)來(lái)存儲(chǔ)ipv4地址,通過(guò)MySQL函數(shù)inet_ntoa和inet_aton來(lái)進(jìn)行轉(zhuǎn)化。Ipv6地址目前沒(méi)有轉(zhuǎn)化函數(shù),需要使用DECIMAL或者兩個(gè)bigINT來(lái)存儲(chǔ)。例如:
SELECT INET_ATON('209.207.224.40');
3520061480
SELECT INET_NTOA(3520061480);
209.207.224.40
4.8 INT[M],M值代表什么含義?
注意數(shù)值類型括號(hào)后面的數(shù)字只是表示寬度而跟存儲(chǔ)范圍沒(méi)有關(guān)系,比如INT(3)默認(rèn)顯示3位,空格補(bǔ)齊,超出時(shí)正常顯示,python、java客戶端等不具備這個(gè)功能。如果采用INT類型,我們都用INT(10)
4.9 不建議使用ENUM、SET類型,使用TINYINT來(lái)代替。
a)ENUM,有三個(gè)問(wèn)題:添加新的值要做DDL,默認(rèn)值問(wèn)題(將一個(gè)非法值插入ENUM(也就是說(shuō),允許的值列之外的字符串),將插入空字符串以作為特殊錯(cuò)誤值),索引值問(wèn)題(插入數(shù)字實(shí)際是插入索引對(duì)應(yīng)的值)
實(shí)例:
drop table if exists t;
create table t(sex enum('0','1'));
insert into t values(1);
insert into t values('3');
select * from t;
+------+
| sex |
+------+
| 0 |
| |
+------+
2 rows in set (0.00 sec)
4.10 盡可能不使用TEXT、BLOB類型。
a) 索引排序問(wèn)題,只能使用max_sort_length的長(zhǎng)度或者手工指定ORDER BY SUBSTRING(column,length)的長(zhǎng)度來(lái)排序
b) Memory引擘不支持text,blog類型,會(huì)在磁盤上生成臨時(shí)表
c) 可能浪費(fèi)更多的空間
d) 可能無(wú)法使用adaptive hash index
e) 導(dǎo)致使用where沒(méi)有索引的語(yǔ)句變慢
4.11 VARCHAR中會(huì)產(chǎn)生額外存儲(chǔ)嗎?
VARCHAR(M),如果M<256時(shí)會(huì)使用一個(gè)字節(jié)來(lái)存儲(chǔ)長(zhǎng)度,如果M>=256則使用兩個(gè)字節(jié)來(lái)存儲(chǔ)長(zhǎng)度。
4.12 表字符集選擇UTF8。
a) 使用utf8字符集,如果是漢字,占3個(gè)字節(jié),但ASCII碼字符還是1個(gè)字節(jié)。
b) 統(tǒng)一,不會(huì)有轉(zhuǎn)換產(chǎn)生亂碼風(fēng)險(xiǎn)
c) 其他地區(qū)的用戶(美國(guó)、印度、臺(tái)灣)無(wú)需安裝簡(jiǎn)體中文支持,就能正常看您的文字,并且不會(huì)出現(xiàn)亂碼
d)ISO-8859-1編碼(latin1)使用了單字節(jié)內(nèi)的所有空間,在支持ISO-8859-1的系統(tǒng)中傳輸和存儲(chǔ)其他任何編碼的字節(jié)流都不會(huì)被拋棄。即把其他任何編碼的字節(jié)流當(dāng)作ISO-8859-1編碼看待都沒(méi)有問(wèn)題,保存的是原封不動(dòng)的字節(jié)流。
4.13 使用VARBINARY存儲(chǔ)變長(zhǎng)字符串。
二進(jìn)制字節(jié)流,不存在編碼問(wèn)題
4.14 為什么建議使用TIMESTAMP來(lái)存儲(chǔ)時(shí)間而不是DATETIME?
DATETIME和TIMESTAMP都是精確到秒,優(yōu)先選擇TIMESTAMP,因?yàn)門IMESTAMP只有4個(gè)字節(jié),而DATETIME8個(gè)字節(jié)。同時(shí)TIMESTAMP具有自動(dòng)賦值以及自動(dòng)更新的特性。
如何使用TIMESTAMP的自動(dòng)賦值屬性?
a) 將當(dāng)前時(shí)間作為ts的默認(rèn)值:ts TIMESTAMP DEFAULTCURRENT_TIMESTAMP。
b)當(dāng)行更新時(shí),更新ts的值:ts TIMESTAMP DEFAULT 0 ONUPDATE CURRENT_TIMESTAMP。
c) 可以將1和2結(jié)合起來(lái):ts TIMESTAMP DEFAULTCURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP。
TIMESTAMP類型保存的值不能比1970早或比2037晚
4.15 建議字段定義為NOT NULL。
a)如果null字段被索引,需要額外的1字節(jié)
b)使索引,索引統(tǒng)計(jì),值的比較變得更復(fù)雜
c)可用'',0代替
d)如果是索引字段,一定要定義為not null
例如:NOT NULL default ''
4.16 禁止在數(shù)據(jù)庫(kù)中使用VARBINARY、BLOB存儲(chǔ)圖片、文件等。
采用分布式文件系統(tǒng)更高效
4.17 為什么MySQL的性能依賴于索引?
MySQL的查詢速度依賴良好的索引設(shè)計(jì),因此索引對(duì)于高性能至關(guān)重要。合理的索引會(huì)加快查詢速度(包括UPDATE和DELETE的速度,MySQL會(huì)將包含該行的page加載到內(nèi)存中,然后進(jìn)行UPDATE或者DELETE操作),不合理的索引會(huì)降低速度。
MySQL索引查找類似于新華字典的拼音和部首查找,當(dāng)拼音和部首索引不存在時(shí),只能通過(guò)一頁(yè)一頁(yè)的翻頁(yè)來(lái)查找。當(dāng)MySQL查詢不能使用索引時(shí),MySQL會(huì)進(jìn)行全表掃描,會(huì)消耗大量的IO。
4.18 為什么一張表中不能存在過(guò)多的索引?
InnoDB的secondaryindex使用b+tree來(lái)存儲(chǔ),因此在UPDATE、DELETE、INSERT的時(shí)候需要對(duì)b+tree進(jìn)行調(diào)整,過(guò)多的索引會(huì)減慢更新的速度。
4.19 EXPLAIN語(yǔ)句
EXPLAIN語(yǔ)句(在MySQL客戶端中執(zhí)行)可以獲得MySQL如何執(zhí)行SELECT語(yǔ)句的信息。通過(guò)對(duì)SELECT語(yǔ)句執(zhí)行EXPLAIN,可以知曉MySQL執(zhí)行該SELECT語(yǔ)句時(shí)是否使用了索引、全表掃描、臨時(shí)表、排序等信息。盡量避免MySQL進(jìn)行全表掃描、使用臨時(shí)表、排序等。詳見(jiàn)官方文檔。
4.20 不建議使用%前綴模糊查詢,例如LIKE “%weibo”。
會(huì)導(dǎo)致全表掃描
4.21 什么是覆蓋索引?
InnoDB 存儲(chǔ)引擎中,secondaryindex(非主鍵索引)中沒(méi)有直接存儲(chǔ)行地址,存儲(chǔ)主鍵值。如果用戶需要查詢secondaryindex中所不包含的數(shù)據(jù)列時(shí),需要先通過(guò)secondaryindex查找到主鍵值,然后再通過(guò)主鍵查詢到其他數(shù)據(jù)列,因此需要查詢兩次。
覆蓋索引的概念就是查詢可以通過(guò)在一個(gè)索引中完成,覆蓋索引效率會(huì)比較高,主鍵查詢是天然的覆蓋索引。
合理的創(chuàng)建索引以及合理的使用查詢語(yǔ)句,當(dāng)使用到覆蓋索引時(shí)可以獲得性能提升。
4.22 UPDATE、DELETE語(yǔ)句不使用LIMIT。
a) 可能導(dǎo)致主從數(shù)據(jù)不一致
b) 會(huì)記錄到錯(cuò)誤日志,導(dǎo)致日志占用大量空間
4.23 為什么需要避免MySQL進(jìn)行隱式類型轉(zhuǎn)化?
因?yàn)镸ySQL進(jìn)行隱式類型轉(zhuǎn)化之后,可能會(huì)將索引字段類型轉(zhuǎn)化成=號(hào)右邊值的類型,導(dǎo)致使用不到索引,原因和避免在索引字段中使用函數(shù)是類似的。
4.24 為什么不建議使用SELECT *?
增加很多不必要的消耗(cpu、io、內(nèi)存、網(wǎng)絡(luò)帶寬);增加了使用覆蓋索引的可能性;當(dāng)表結(jié)構(gòu)發(fā)生改變時(shí),前段也需要更新。
4.25 為什么不能使用ORDER BY rand()?
因?yàn)镺RDER BYrand()會(huì)將數(shù)據(jù)從磁盤中讀取,進(jìn)行排序,會(huì)消耗大量的IO和CPU,可以在程序中獲取一個(gè)rand值,然后通過(guò)在從數(shù)據(jù)庫(kù)中獲取對(duì)應(yīng)的值。
4.26 MySQL中如何進(jìn)行分頁(yè)?
假如有類似下面分頁(yè)語(yǔ)句:
SELECT * FROM table ORDER BY TIME DESC LIMIT 10000,10;
這種分頁(yè)方式會(huì)導(dǎo)致大量的io,因?yàn)镸ySQL使用的是提前讀取策略。
推薦分頁(yè)方式:
SELECT * FROM table where id >=(select id from table order by id limit 10000,1)limit 10;
SELECT * FROM table inner JOIN(SELECT id FROM table ORDER BY id LIMIT 10000,10) as t USING(id)
4.27 為什么避免使用復(fù)雜的SQL?
拒絕使用復(fù)雜的SQL,將大的SQL拆分成多條簡(jiǎn)單SQL分步執(zhí)行。原因:簡(jiǎn)單的SQL容易使用到MySQL的querycache;減少鎖表時(shí)間特別是MyISAM;可以使用多核cpu。
2. InnoDB存儲(chǔ)引擎為什么避免使用COUNT(*)?
InnoDB表避免使用COUNT(*)操作,計(jì)數(shù)統(tǒng)計(jì)實(shí)時(shí)要求較強(qiáng)可以使用memcache或者redis,非實(shí)時(shí)統(tǒng)計(jì)可以使用單獨(dú)統(tǒng)計(jì)表,定時(shí)更新。