原文:https://mp.weixin.qq.com/s/un-k1P2wCURUem4XikKX7Q
前言
SELECT語句 - 語法順序:
SELECT語句 - 執(zhí)行順序:
SQL優(yōu)化策略
一判沟、避免不走索引的場景
二您朽、SELECT語句其他優(yōu)化
三算吩、增刪改 DML 語句優(yōu)化
四、查詢條件優(yōu)化
五笋妥、建表優(yōu)化
有朋友疑問到浸赫,SQL優(yōu)化真的有這么重要么?如下圖所示,SQL優(yōu)化在提升系統(tǒng)性能中是:(成本最低 && 優(yōu)化效果最明顯) 的途徑贴浙。如果你的團隊在SQL優(yōu)化這方面搞得很優(yōu)秀,對你們整個大型系統(tǒng)可用性方面無疑是一個質(zhì)的跨越署恍,真的能讓你們老板省下不止幾沓子錢崎溃。
優(yōu)化成本:硬件>系統(tǒng)配置>數(shù)據(jù)庫表結(jié)構>SQL及索引。
優(yōu)化效果:硬件<系統(tǒng)配置<數(shù)據(jù)庫表結(jié)構<SQL及索引盯质。
String result = "嗯袁串,不錯,";
if ("SQL優(yōu)化經(jīng)驗足") {
if ("熟悉事務鎖") {
if ("并發(fā)場景處理666") {
if ("會打王者榮耀") {
result += "明天入職"
}
}
}
} else {
result += "先回去等消息吧";
}
Logger.info("面試官:" + result );
別看了呼巷,上面這是一道送命題囱修。
好了我們言歸正傳,首先王悍,對于MySQL層優(yōu)化我一般遵從五個原則:
減少數(shù)據(jù)訪問:設置合理的字段類型破镰,啟用壓縮,通過索引訪問等減少磁盤IO
返回更少的數(shù)據(jù):只返回需要的字段和數(shù)據(jù)分頁處理 減少磁盤io及網(wǎng)絡io
減少交互次數(shù):批量DML操作压储,函數(shù)存儲等減少數(shù)據(jù)連接次數(shù)
減少服務器CPU開銷:盡量減少數(shù)據(jù)庫排序操作以及全表查詢鲜漩,減少cpu 內(nèi)存占用
利用更多資源:使用表分區(qū),可以增加并行操作集惋,更大限度利用cpu資源
總結(jié)到SQL優(yōu)化中孕似,就三點:
最大化利用索引;
盡可能避免全表掃描刮刑;
減少無效數(shù)據(jù)的查詢鳞青;
理解SQL優(yōu)化原理 ,首先要搞清楚SQL執(zhí)行順序:
SELECT語句 - 語法順序:
1. SELECT
2. DISTINCT <select_list>
3. FROM <left_table>
4. <join_type> JOIN <right_table>
5. ON <join_condition>
6. WHERE <where_condition>
7. GROUP BY <group_by_list>
8. HAVING <having_condition>
9. ORDER BY <order_by_condition>
10.LIMIT <limit_number>
SELECT語句 - 執(zhí)行順序:
FROM
<表名> # 選取表为朋,將多個表數(shù)據(jù)通過笛卡爾積變成一個表臂拓。
ON
<篩選條件> # 對笛卡爾積的虛表進行篩選
**JOIN **<join, left join, right join...>
<join表> # 指定join,用于添加數(shù)據(jù)到on之后的虛表中习寸,例如left join會將左表的剩余數(shù)據(jù)添加到虛表中
WHERE
<where條件> # 對上述虛表進行篩選
GROUP BY
<分組條件> # 分組
<SUM()等聚合函數(shù)> # 用于having子句進行判斷胶惰,在書寫上這類聚合函數(shù)是寫在having判斷里面的
HAVING
<分組篩選> # 對分組后的結(jié)果進行聚合篩選
SELECT
<返回數(shù)據(jù)列表> # 返回的單列必須在group by子句中,聚合函數(shù)除外
DISTINCT
數(shù)據(jù)除重
ORDER BY
<排序條件> # 排序
LIMIT
<行數(shù)限制>
SQL優(yōu)化策略
聲明:以下SQL優(yōu)化策略適用于數(shù)據(jù)量較大的場景下霞溪,如果數(shù)據(jù)量較小孵滞,沒必要以此為準,以免畫蛇添足鸯匹。
一坊饶、避免不走索引的場景
1. 盡量避免在字段開頭模糊查詢,會導致數(shù)據(jù)庫引擎放棄索引進行全表掃描殴蓬。如下:
SELECT * FROM t WHERE username LIKE '%陳%'
優(yōu)化方式:盡量在字段后面使用模糊查詢匿级。如下:
SELECT * FROM t WHERE username LIKE '陳%'
如果需求是要在前面使用模糊查詢蟋滴,
使用MySQL內(nèi)置函數(shù)INSTR(str,substr) 來匹配,作用類似于java中的indexOf()痘绎,查詢字符串出現(xiàn)的角標位置
使用FullText全文索引津函,用match against 檢索
數(shù)據(jù)量較大的情況,建議引用ElasticSearch孤页、solr尔苦,億級數(shù)據(jù)量檢索速度秒級
當表數(shù)據(jù)量較少(幾千條兒那種),別整花里胡哨的行施,直接用like '%xx%'允坚。
2. 盡量避免使用in 和not in,會導致引擎走全表掃描蛾号。如下:
SELECT * FROM t WHERE id IN (2,3)
優(yōu)化方式:如果是連續(xù)數(shù)值屋讶,可以用between代替。如下:
SELECT * FROM t WHERE id BETWEEN 2 AND 3
如果是子查詢须教,可以用exists代替皿渗。如下:
-- 不走索引
select * from A where A.id in (select id from B);
-- 走索引
select * from A where exists (select * from B where B.id = A.id);
3. 盡量避免使用 or,會導致數(shù)據(jù)庫引擎放棄索引進行全表掃描轻腺。如下:
SELECT * FROM t WHERE id = 1 OR id = 3
優(yōu)化方式:可以用union代替or乐疆。如下:
SELECT * FROM t WHERE id = 1
UNION
SELECT * FROM t WHERE id = 3
4. 盡量避免進行null值的判斷,會導致數(shù)據(jù)庫引擎放棄索引進行全表掃描贬养。如下:
SELECT * FROM t WHERE score IS NULL
優(yōu)化方式:可以給字段添加默認值0挤土,對0值進行判斷。如下:
SELECT * FROM t WHERE score = 0
5.盡量避免在where條件中等號的左側(cè)進行表達式误算、函數(shù)操作仰美,會導致數(shù)據(jù)庫引擎放棄索引進行全表掃描。
可以將表達式儿礼、函數(shù)操作移動到等號右側(cè)咖杂。如下:
-- 全表掃描
SELECT * FROM T WHERE score/10 = 9
-- 走索引
SELECT * FROM T WHERE score = 10*9
6. 當數(shù)據(jù)量大時,避免使用where 1=1的條件蚊夫。通常為了方便拼裝查詢條件诉字,我們會默認使用該條件,數(shù)據(jù)庫引擎會放棄索引進行全表掃描知纷。如下:
SELECT username, age, sex FROM T WHERE 1=1
優(yōu)化方式:用代碼拼裝sql時進行判斷壤圃,沒 where 條件就去掉 where,有where條件就加 and琅轧。
搜索Java知音公眾號伍绳,回復“后端面試”,送你一份Java面試題寶典.pdf
7. 查詢條件不能用 <> 或者 !=
使用索引列作為條件進行查詢時乍桂,需要避免使用<>或者!=等判斷條件冲杀。如確實業(yè)務需要效床,使用到不等于符號,需要在重新評估索引建立漠趁,避免在此字段上建立索引,改由查詢條件中其他索引字段代替忍疾。
8. where條件僅包含復合索引非前置列
如下:復合(聯(lián)合)索引包含key_part1闯传,key_part2,key_part3三列卤妒,但SQL語句沒有包含索引前置列"key_part1"甥绿,按照MySQL聯(lián)合索引的最左匹配原則,不會走聯(lián)合索引则披。
select col1 from table where key_part2=1 and key_part3=2
9. 隱式類型轉(zhuǎn)換造成不使用索引
如下SQL語句由于索引對列類型為varchar共缕,但給定的值為數(shù)值,涉及隱式類型轉(zhuǎn)換士复,造成不能正確走索引图谷。
select col1 from table where col_varchar=123;
10. order by 條件要與where中條件一致,否則order by不會利用索引進行排序
-- 不走age索引
SELECT * FROM t order by age;
-- 走age索引
SELECT * FROM t where age > 0 order by age;
對于上面的語句阱洪,數(shù)據(jù)庫的處理順序是:
第一步:根據(jù)where條件和統(tǒng)計信息生成執(zhí)行計劃便贵,得到數(shù)據(jù)。
第二步:將得到的數(shù)據(jù)排序冗荸。當執(zhí)行處理數(shù)據(jù)(order by)時承璃,數(shù)據(jù)庫會先查看第一步的執(zhí)行計劃,看order by 的字段是否在執(zhí)行計劃中利用了索引蚌本。如果是盔粹,則可以利用索引順序而直接取得已經(jīng)排好序的數(shù)據(jù)。如果不是程癌,則重新進行排序操作舷嗡。
第三步:返回排序后的數(shù)據(jù)。
當order by 中的字段出現(xiàn)在where條件中時嵌莉,才會利用索引而不再二次排序咬崔,更準確的說,order by 中的字段在執(zhí)行計劃中利用了索引時烦秩,不用排序操作垮斯。
這個結(jié)論不僅對order by有效,對其他需要排序的操作也有效只祠。比如group by 兜蠕、union 、distinct等抛寝。
11. 正確使用hint優(yōu)化語句
MySQL中可以使用hint指定優(yōu)化器在執(zhí)行時選擇或忽略特定的索引熊杨。一般而言曙旭,處于版本變更帶來的表結(jié)構索引變化,更建議避免使用hint晶府,而是通過Analyze table多收集統(tǒng)計信息桂躏。但在特定場合下,指定hint可以排除其他索引干擾而指定更優(yōu)的執(zhí)行計劃川陆。
USE INDEX 在你查詢語句中表名的后面剂习,添加 USE INDEX 來提供希望 MySQL 去參考的索引列表,就可以讓 MySQL 不再考慮其他可用的索引较沪。例子: SELECT col1 FROM table USE INDEX (mod_time, name)...
IGNORE INDEX 如果只是單純的想讓 MySQL 忽略一個或者多個索引鳞绕,可以使用 IGNORE INDEX 作為 Hint。例子: SELECT col1 FROM table IGNORE INDEX (priority) ...
FORCE INDEX 為強制 MySQL 使用一個特定的索引尸曼,可在查詢中使用FORCE INDEX 作為Hint们何。例子: SELECT col1 FROM table FORCE INDEX (mod_time) ...
在查詢的時候,數(shù)據(jù)庫系統(tǒng)會自動分析查詢語句控轿,并選擇一個最合適的索引冤竹。但是很多時候,數(shù)據(jù)庫系統(tǒng)的查詢優(yōu)化器并不一定總是能使用最優(yōu)索引茬射。如果我們知道如何選擇索引贴见,可以使用FORCE INDEX強制查詢使用指定的索引。
例如:
SELECT * FROM students FORCE INDEX (idx_class_id) WHERE class_id = 1 ORDER BY id DESC;
二躲株、SELECT語句其他優(yōu)化
**1. 避免出現(xiàn)select ***
首先片部,select * 操作在任何類型數(shù)據(jù)庫中都不是一個好的SQL編寫習慣。
使用select * 取出全部列霜定,會讓優(yōu)化器無法完成索引覆蓋掃描這類優(yōu)化档悠,會影響優(yōu)化器對執(zhí)行計劃的選擇,也會增加網(wǎng)絡帶寬消耗望浩,更會帶來額外的I/O,內(nèi)存和CPU消耗辖所。
建議提出業(yè)務實際需要的列數(shù),將指定列名以取代select *磨德。
2. 避免出現(xiàn)不確定結(jié)果的函數(shù)
特定針對主從復制這類業(yè)務場景缘回。由于原理上從庫復制的是主庫執(zhí)行的語句,使用如now()典挑、rand()酥宴、sysdate()、current_user()等不確定結(jié)果的函數(shù)很容易導致主庫與從庫相應的數(shù)據(jù)不一致您觉。另外不確定值的函數(shù),產(chǎn)生的SQL語句無法利用query cache拙寡。
3.多表關聯(lián)查詢時,小表在前琳水,大表在后肆糕。
在MySQL中般堆,執(zhí)行 from 后的表關聯(lián)查詢是從左往右執(zhí)行的(Oracle相反),第一張表會涉及到全表掃描诚啃,所以將小表放在前面淮摔,先掃小表,掃描快效率較高始赎,在掃描后面的大表和橙,或許只掃描大表的前100行就符合返回條件并return了。
例如:表1有50條數(shù)據(jù)极阅,表2有30億條數(shù)據(jù)胃碾;如果全表掃描表2涨享,你品筋搏,那就先去吃個飯再說吧是吧。
4. 使用表的別名
當在SQL語句中連接多個表時厕隧,請使用表的別名并把別名前綴于每個列名上奔脐。這樣就可以減少解析的時間并減少哪些友列名歧義引起的語法錯誤。
5. 用where字句替換HAVING字句
避免使用HAVING字句吁讨,因為HAVING只會在檢索出所有記錄之后才對結(jié)果集進行過濾髓迎,而where則是在聚合前刷選記錄,如果能通過where字句限制記錄的數(shù)目建丧,那就能減少這方面的開銷排龄。HAVING中的條件一般用于聚合函數(shù)的過濾,除此之外翎朱,應該將條件寫在where字句中橄维。
where和having的區(qū)別:where后面不能使用組函數(shù)
6.調(diào)整Where字句中的連接順序
MySQL采用從左往右,自上而下的順序解析where子句拴曲。根據(jù)這個原理争舞,應將過濾數(shù)據(jù)多的條件往前放,最快速度縮小結(jié)果集澈灼。
三竞川、增刪改 DML 語句優(yōu)化
1. 大批量插入數(shù)據(jù)
如果同時執(zhí)行大量的插入,建議使用多個值的INSERT語句(方法二)叁熔。這比使用分開INSERT語句快(方法一)委乌,一般情況下批量插入效率有幾倍的差別。
方法一:
insert into T values(1,2);
insert into T values(1,3);
insert into T values(1,4);
方法二:
Insert into T values(1,2),(1,3),(1,4);
選擇后一種方法的原因有三荣回。
減少SQL語句解析的操作福澡,MySQL沒有類似Oracle的share pool,采用方法二驹马,只需要解析一次就能進行數(shù)據(jù)的插入操作革砸;
在特定場景可以減少對DB連接次數(shù)
SQL語句較短除秀,可以減少網(wǎng)絡傳輸?shù)腎O。
2. 適當使用commit
適當使用commit可以釋放事務占用的資源而減少消耗算利,commit后能釋放的資源如下:
事務占用的undo數(shù)據(jù)塊册踩;
事務在redo log中記錄的數(shù)據(jù)塊;
釋放事務施加的效拭,減少鎖爭用影響性能暂吉。特別是在需要使用delete刪除大量數(shù)據(jù)的時候,必須分解刪除量并定期commit缎患。
3. 避免重復查詢更新的數(shù)據(jù)
針對業(yè)務中經(jīng)常出現(xiàn)的更新行同時又希望獲得改行信息的需求慕的,MySQL并不支持PostgreSQL那樣的UPDATE RETURNING語法,在MySQL中可以通過變量實現(xiàn)挤渔。
例如肮街,更新一行記錄的時間戳,同時希望查詢當前記錄中存放的時間戳是什么判导,簡單方法實現(xiàn):
Update t1 set time=now() where col1=1;
Select time from t1 where id =1;
使用變量嫉父,可以重寫為以下方式:
Update t1 set time=now () where col1=1 and @now: = now ();
Select @now;
前后二者都需要兩次網(wǎng)絡來回,但使用變量避免了再次訪問數(shù)據(jù)表眼刃,特別是當t1表數(shù)據(jù)量較大時绕辖,后者比前者快很多。
4.查詢優(yōu)先還是更新(insert擂红、update仪际、delete)優(yōu)先
MySQL 還允許改變語句調(diào)度的優(yōu)先級,它可以使來自多個客戶端的查詢更好地協(xié)作昵骤,這樣單個客戶端就不會由于鎖定而等待很長時間树碱。改變優(yōu)先級還可以確保特定類型的查詢被處理得更快。我們首先應該確定應用的類型涉茧,判斷應用是以查詢?yōu)橹鬟€是以更新為主的赴恨,是確保查詢效率還是確保更新的效率,決定是查詢優(yōu)先還是更新優(yōu)先伴栓。
下面我們提到的改變調(diào)度策略的方法主要是針對只存在表鎖的存儲引擎伦连,比如 MyISAM 、MEMROY钳垮、MERGE惑淳,對于Innodb 存儲引擎,語句的執(zhí)行是由獲得行鎖的順序決定的饺窿。MySQL 的默認的調(diào)度策略可用總結(jié)如下:
1)寫入操作優(yōu)先于讀取操作歧焦。
2)對某張數(shù)據(jù)表的寫入操作某一時刻只能發(fā)生一次,寫入請求按照它們到達的次序來處理。
3)對某張數(shù)據(jù)表的多個讀取操作可以同時地進行绢馍。MySQL 提供了幾個語句調(diào)節(jié)符向瓷,允許你修改它的調(diào)度策略:
LOW_PRIORITY關鍵字應用于DELETE、INSERT舰涌、LOAD DATA猖任、REPLACE和UPDATE;
HIGH_PRIORITY關鍵字應用于SELECT和INSERT語句瓷耙;
DELAYED關鍵字應用于INSERT和REPLACE語句朱躺。
如果寫入操作是一個 LOW_PRIORITY(低優(yōu)先級)請求,那么系統(tǒng)就不會認為它的優(yōu)先級高于讀取操作搁痛。在這種情況下长搀,如果寫入者在等待的時候,第二個讀取者到達了鸡典,那么就允許第二個讀取者插到寫入者之前源请。只有在沒有其它的讀取者的時候,才允許寫入者開始操作轿钠。這種調(diào)度修改可能存在 LOW_PRIORITY寫入操作永遠被阻塞的情況巢钓。
SELECT 查詢的HIGH_PRIORITY(高優(yōu)先級)關鍵字也類似病苗。它允許SELECT 插入正在等待的寫入操作之前疗垛,即使在正常情況下寫入操作的優(yōu)先級更高。另外一種影響是硫朦,高優(yōu)先級的 SELECT 在正常的 SELECT 語句之前執(zhí)行贷腕,因為這些語句會被寫入操作阻塞。如果希望所有支持LOW_PRIORITY 選項的語句都默認地按照低優(yōu)先級來處理咬展,那么 請使用--low-priority-updates 選項來啟動服務器泽裳。通過使用 INSERTHIGH_PRIORITY 來把 INSERT 語句提高到正常的寫入優(yōu)先級,可以消除該選項對單個INSERT語句的影響破婆。
搜索Java知音公眾號涮总,回復“后端面試”,送你一份Java面試題寶典.pdf
四祷舀、查詢條件優(yōu)化
1. 對于復雜的查詢瀑梗,可以使用中間臨時表 暫存數(shù)據(jù)
2. 優(yōu)化group by語句
默認情況下,MySQL 會對GROUP BY分組的所有值進行排序裳扯,如 “GROUP BY col1抛丽,col2,....;” 查詢的方法如同在查詢中指定 “ORDER BY col1饰豺,col2亿鲜,...;” 如果顯式包括一個包含相同的列的 ORDER BY子句,MySQL 可以毫不減速地對它進行優(yōu)化冤吨,盡管仍然進行排序蒿柳。
因此饶套,如果查詢包括 GROUP BY 但你并不想對分組的值進行排序,你可以指定 ORDER BY NULL禁止排序垒探。例如:
SELECT col1, col2, COUNT(*) FROM table GROUP BY col1, col2 ORDER BY NULL ;
3. 優(yōu)化join語句
MySQL中可以通過子查詢來使用 SELECT 語句來創(chuàng)建一個單列的查詢結(jié)果凤跑,然后把這個結(jié)果作為過濾條件用在另一個查詢中。使用子查詢可以一次性的完成很多邏輯上需要多個步驟才能完成的 SQL 操作叛复,同時也可以避免事務或者表鎖死仔引,并且寫起來也很容易。但是褐奥,有些情況下咖耘,子查詢可以被更有效率的連接(JOIN)..替代。
例子:假設要將所有沒有訂單記錄的用戶取出來撬码,可以用下面這個查詢完成:
SELECT col1 FROM customerinfo WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )
如果使用連接(JOIN).. 來完成這個查詢工作儿倒,速度將會有所提升。尤其是當 salesinfo表中對 CustomerID 建有索引的話呜笑,性能將會更好夫否,查詢?nèi)缦拢?/p>
SELECT col1 FROM customerinfo
LEFT JOIN salesinfoON customerinfo.CustomerID=salesinfo.CustomerID
WHERE salesinfo.CustomerID IS NULL
連接(JOIN).. 之所以更有效率一些,是因為 MySQL 不需要在內(nèi)存中創(chuàng)建臨時表來完成這個邏輯上的需要兩個步驟的查詢工作叫胁。
4. 優(yōu)化union查詢
MySQL通過創(chuàng)建并填充臨時表的方式來執(zhí)行union查詢凰慈。除非確實要消除重復的行,否則建議使用union all驼鹅。原因在于如果沒有all這個關鍵詞微谓,MySQL會給臨時表加上distinct選項,這會導致對整個臨時表的數(shù)據(jù)做唯一性校驗输钩,這樣做的消耗相當高豺型。
高效:
SELECT COL1, COL2, COL3 FROM TABLE WHERE COL1 = 10
UNION ALL
SELECT COL1, COL2, COL3 FROM TABLE WHERE COL3= 'TEST';
低效:
SELECT COL1, COL2, COL3 FROM TABLE WHERE COL1 = 10
UNION
SELECT COL1, COL2, COL3 FROM TABLE WHERE COL3= 'TEST';
5.拆分復雜SQL為多個小SQL,避免大事務
簡單的SQL容易使用到MySQL的QUERY CACHE买乃;
減少鎖表時間特別是使用MyISAM存儲引擎的表姻氨;
可以使用多核CPU。
6. 使用truncate代替delete
當刪除全表中記錄時剪验,使用delete語句的操作會被記錄到undo塊中肴焊,刪除記錄也記錄binlog,當確認需要刪除全表時碉咆,會產(chǎn)生很大量的binlog并占用大量的undo數(shù)據(jù)塊抖韩,此時既沒有很好的效率也占用了大量的資源。
使用truncate替代疫铜,不會記錄可恢復的信息茂浮,數(shù)據(jù)不能被恢復。也因此使用truncate操作有其極少的資源占用與極快的時間。另外席揽,使用truncate可以回收表的水位顽馋,使自增字段值歸零。
7. 使用合理的分頁方式以提高分頁效率
使用合理的分頁方式以提高分頁效率 針對展現(xiàn)等分頁需求幌羞,合適的分頁方式能夠提高分頁的效率寸谜。
案例1:
select * from t where thread_id = 10000 and deleted = 0
order by gmt_create asc limit 0, 15;
上述例子通過一次性根據(jù)過濾條件取出所有字段進行排序返回。數(shù)據(jù)訪問開銷=索引IO+索引全部記錄結(jié)果對應的表數(shù)據(jù)IO属桦。因此熊痴,該種寫法越翻到后面執(zhí)行效率越差,時間越長聂宾,尤其表數(shù)據(jù)量很大的時候果善。
適用場景:當中間結(jié)果集很小(10000行以下)或者查詢條件復雜(指涉及多個不同查詢字段或者多表連接)時適用系谐。
案例2:
select t.* from (select id from t where thread_id = 10000 and deleted = 0
order by gmt_create asc limit 0, 15) a, t
where a.id = t.id;
上述例子必須滿足t表主鍵是id列巾陕,且有覆蓋索引secondary key:(thread_id, deleted, gmt_create)。通過先根據(jù)過濾條件利用覆蓋索引取出主鍵id進行排序纪他,再進行join操作取出其他字段鄙煤。數(shù)據(jù)訪問開銷=索引IO+索引分頁后結(jié)果(例子中是15行)對應的表數(shù)據(jù)IO。因此茶袒,該寫法每次翻頁消耗的資源和時間都基本相同梯刚,就像翻第一頁一樣。
適用場景:當查詢和排序字段(即where子句和order by子句涉及的字段)有對應覆蓋索引時弹谁,且中間結(jié)果集很大的情況時適用乾巧。
五句喜、建表優(yōu)化
1. 在表中建立索引预愤,優(yōu)先考慮where、order by使用到的字段咳胃。
2. 盡量使用數(shù)字型字段(如性別植康,男:1 女:2),若只含數(shù)值信息的字段盡量不要設計為字符型展懈,這會降低查詢和連接的性能销睁,并會增加存儲開銷。
這是因為引擎在處理查詢和連接時會 逐個比較字符串中每一個字符存崖,而對于數(shù)字型而言只需要比較一次就夠了冻记。
3. 查詢數(shù)據(jù)量大的表 會造成查詢緩慢。主要的原因是掃描行數(shù)過多来惧。這個時候可以通過程序冗栗,分段分頁進行查詢,循環(huán)遍歷,將結(jié)果合并處理進行展示隅居。要查詢100000到100050的數(shù)據(jù)钠至,如下:
SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY ID ASC) AS rowid,*
FROM infoTab)t WHERE t.rowid > 100000 AND t.rowid <= 100050
4. 用varchar/nvarchar 代替 char/nchar
盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長字段存儲空間小胎源,可以節(jié)省存儲空間棉钧,其次對于查詢來說,在一個相對較小的字段內(nèi)搜索效率顯然要高些涕蚤。
不要以為 NULL 不需要空間宪卿,比如:char(100) 型,在字段建立時万栅,空間就固定了呐萨, 不管是否插入值(NULL也包含在內(nèi))减途,都是占用 100個字符的空間的,如果是varchar這樣的變長字段, null 不占用空間恭金。