1.對查詢進行優化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
2.應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t where num is null可以在num上設置默認值0,確保表中num列沒有null值,然后這樣查詢:select id from t where num=0
3.應盡量避免在 where 子句中使用!=或<>操作符,否則引擎將放棄使用索引而進行全表掃描。
4.應盡量避免在 where 子句中使用or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t where num=10 or num=20可以這樣查詢:select id from t where num=10 union all select id from t where num=20
5.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
6.下面的查詢也將導致全表掃描:select id from t where name like ‘%李%’若要提高效率,可以考慮全文檢索。
- 如果在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變量,但優化程序不能將訪問計划的選擇推遲到運行時;它必須在編譯時進行選擇。然 而,如果在編譯時建立訪問計划,變量的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:select id from t where num=@num可以改為強制查詢使用索引:select id from t with(index(索引名)) where num=@num
8.應盡量避免在 where 子句中對字段進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:select id from t where num/2=100應改為:select id from t where num=100*2
9.應盡量避免在where子句中對字段進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:select id from t where substring(name,1,3)=’abc’ ,name以abc開頭的id應改為:
select id from t where name like ‘abc%’
10.不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
11.在使用索引字段作為條件時,如果該索引是復合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應盡可能的讓字段順序與索引順序相一致。
12.不要寫一些沒有意義的查詢,如需要生成一個空表結構:select col1,col2 into #t from t where 1=0
這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:
create table #t(…)
13.很多時候用 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)
14.並不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,如一表中有字段sex,male、female幾乎各一半,那么即使在sex上建了索引也對查詢效率起不了作用。
-
索引並不是越多越好,索引固然可 以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有 必要。
-
應盡可能的避免更新 clustered 索引數據列,因為 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引數據列,那么需要考慮是否應將該索引建為 clustered 索引。
17.盡量使用數字型字段,若只含數值信息的字段盡量不要設計為字符型,這會降低查詢和連接的性能,並會增加存儲開銷。這是因為引擎在處理查詢和連接時會逐個比較字符串中每一個字符,而對於數字型而言只需要比較一次就夠了.
18.盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長字段存儲空間小,可以節省存儲空間,其次對於查詢來說,在一個相對較小的字段內搜索效率顯然要高些。
19.任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。
20.盡量使用表變量來代替臨時表。如果表變量包含大量數據,請注意索引非常有限(只有主鍵索引)。
21.避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。
22.臨時表並不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重復引用大型表或常用表中的某個數據集時。但是,對於一次性事件,最好使用導出表。
23.在新建臨時表時,如果一次性插入數據量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然后insert。
24.如果使用到了臨時表,在存儲過程的最后務必將所有的臨時表顯式刪除,先 truncate table ,然后 drop table ,這樣可以避免系統表的較長時間鎖定。
25.盡量避免使用游標,因為游標的效率較差,如果游標操作的數據超過1萬行,那么就應該考慮改寫。
26.使用基於游標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。
- 與臨時表一樣,游標並不是不可使 用。對小型數據集使用 FAST_FORWARD 游標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括“合計”的例程通常要比使用游標執行的速度快。如果開發時 間允許,基於游標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。
28.在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句后向客戶端發送DONE_IN_PROC 消息。
29.盡量避免大事務操作,提高系統並發能力.
30.盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。
====================================
1、分庫分表
很明顯,一個主表(也就是很重要的表,例如用戶表)無限制的增長勢必嚴重影響性能,分庫與分表是一個很不錯的解決途徑,也就是性能優化途徑,現在的案例是我們有一個1000多萬條記錄的用戶表members,查詢起來非常之慢,同事的做法是將其散列到100個表中,分別從members0到members99,然后根據mid分發記錄到這些表中,牛逼的代碼大概是這樣子:
<?php
for($i=0;$i< 100; $i++ ){ //echo "CREATE TABLE db2.members{$i} LIKE db1.members<br>"; echo "INSERT INTO members{$i} SELECT * FROM members WHERE mid0={$i}<br>"; } ?>
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
2、不停機修改MySQL表結構
同樣還是members表,前期設計的表結構不盡合理,隨着數據庫不斷運行,其冗余數據也是增長巨大,同事使用了下面的方法來處理:
先創建一個臨時表:
CREATE TABLE members_tmp LIKE members
- 1
- 1
然后修改members_tmp的表結構為新結構,接着使用上面那個for循環來導出數據,因為1000萬的數據一次性導出是不對的,mid是主鍵,一個區間一個區間的導,基本是一次導出5萬條吧,這里略去了
接着重命名將新表替換上去:
RENAME TABLE members TO members_bak,members_tmp TO members;
就是這樣,基本可以做到無損失,無需停機更新表結構,但實際上RENAME期間表是被鎖死的,所以選擇在線少的時候操作是一個技巧。經過這個操作,使得原先8G多的表,一下子變成了2G多
另外還講到了mysql中float字段類型的時候出現的詭異現象,就是在pma中看到的數字根本不能作為條件來查詢
3、常用SQL語句優化:
數據庫(表)設計合理
我們的表設計要符合3NF 3范式(規范的模式) , 有時我們需要適當的逆范式
sql語句的優化(索引,常用小技巧.) 數據的配置(緩存設大) 適當硬件配置和操作系統 (讀寫分離.)
數據的3NF
1NF :就是具有原子性,不可分割.(只要使用的是關系性數據庫,就自動符合)
2NF: 在滿足1NF 的基礎上,我們考慮是否滿足2NF: 只要表的記錄滿足唯一性,也是說,你的同一張表,不可能出現完全相同的記錄, 一般說我們在 表中設計一個主鍵即可.
3NF: 在滿足2NF 的基礎上,我們考慮是否滿足3NF:即我們的字段信息可以通過關聯的關系,派生即可.(通常我們通過外鍵來處理)
逆范式: 為什么需呀逆范式:
(相冊的功能對應數據庫的設計)
適當的逆范式.
sql語句的優化
sql語句有幾類
ddl (數據定義語言) [create alter drop]
dml(數據操作語言)[insert delete upate ]
select
dtl(數據事務語句) [commit rollback savepoint]
dcl(數據控制語句) [grant revoke]
show status命令
該命令可以顯示你的mysql數據庫的當前狀態.我們主要關心的是 “com”開頭的指令
show status like ‘Com%’ <=> show session status like ‘Com%’ //顯示當前控制台的情況 show global status like ‘Com%’ ; //顯示數據庫從啟動到 查詢的次數
- 1
- 2
- 3
- 1
- 2
- 3
顯示連接數據庫次數
show status like 'Connections';
- 1
- 1
這里我們優化的重點是在 慢查詢. (在默認情況下是10 ) mysql5.5.19
顯示查看慢查詢的情況
show variables like ‘long_query_time’
- 1
- 1
為了教學,我們搞一個海量表(mysql存儲過程)
目的,就是看看怎樣處理,在海量表中,查詢的速度很快!
select * from emp where empno=123456;
- 1
- 1
需求:如何在一個項目中,找到慢查詢的select , mysql數據庫支持把慢查詢語句,記錄到日志中,程序員分析. (但是注意,默認情況下不啟動.)
步驟:
要這樣啟動mysql
進入到 mysql安裝目錄
- 啟動 xx>bin\mysqld.exe –slow-query-log 這點注意
測試 ,比如我們把
select * from emp where empno=34678 ;
- 1
- 1
用了1.5秒,我現在優化.
快速體驗: 在emp表的 empno建立索引.
alter table emp add primary key(empno);
- 1
- 1
//刪除主鍵索引
alter table emp drop primary key
- 1
- 1
然后,再查速度變快.
l 索引的原理
介紹一款非常重要工具explain, 這個分析工具可以對 sql語句進行分析,可以預測你的sql執行的效率.
他的基本用法是:
explain sql語句\G
//根據返回的信息,我們可知,該sql語句是否使用索引,從多少記錄中取出,可以看到排序的方式.
l 在什么列上添加索引比較合適
① 在經常查詢的列上加索引.
② 列的數據,內容就只有少數幾個值,不太適合加索引.
③ 內容頻繁變化,不合適加索引
l 索引的種類
① 主鍵索引 (把某列設為主鍵,則就是主鍵索引)
② 唯一索引(unique) (即該列具有唯一性,同時又是索引)
③ index (普通索引)
④ 全文索引(FULLTEXT)
select * from article where content like ‘%李連傑%’;
- 1
- 1
hello, i am a boy
l 你好,我是一個男孩 =>中文 sphinx
⑤ 復合索引(多列和在一起)
create index myind on 表名 (列1,列2);
l 如何創建索引
如果創建unique / 普通/fulltext 索引
-
create [unique|FULLTEXT] index 索引名 on 表名 (列名…)
-
alter table 表名 add index 索引名 (列名…)
//如果要添加主鍵索引
alter table 表名 add primary key (列…)
刪除索引
drop index 索引名 on 表名 alter table 表名 drop index index_name; alter table 表名 drop primary key
- 1
- 2
- 3
- 1
- 2
- 3
顯示索引
show index(es) from 表名 show keys from 表名 desc 表名
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
如何查詢某表的索引
show indexes from 表名
l 使用索引的注意事項
查詢要使用索引最重要的條件是查詢條件中需要使用索引。
下列幾種情況下有可能使用到索引:
1,對於創建的多列索引,只要查詢條件使用了最左邊的列,索引一般就會被使用。
2,對於使用like的查詢,查詢如果是 ‘�a’ 不會使用到索引 aaa%’ 會使用到索引。
下列的表將不使用索引:
1,如果條件中有or,即使其中有條件帶索引也不會使用。
2,對於多列索引,不是使用的第一部分,則不會使用索引。
3,like查詢是以%開頭
4,如果列類型是字符串,那一定要在條件中將數據使用引號引用起來。否則不使用索引。
5,如果mysql估計使用全表掃描要比使用索引快,則不使用索引。
l 如何檢測你的索引是否有效
結論: Handler_read_key 越大越少
Handler_read_rnd_next 越小越好
fdisk
find
l MyISAM 和 Innodb區別是什么
MyISAM 不支持外鍵, Innodb支持
MyISAM 不支持事務,不支持外鍵.
對數據信息的存儲處理方式不同.(如果存儲引擎是MyISAM的,則創建一張表,對於三個文件..,如果是Innodb則只有一張文件 *.frm,數據存放到ibdata1)
對於 MyISAM 數據庫,需要定時清理
optimize table 表名
l 常見的sql優化手法
使用order by null 禁用排序
比如 select * from dept group by ename order by null
在精度要求高的應用中,建議使用定點數(decimal)來存儲數值,以保證結果的准確性
3. 如果字段是字符類型的索引,用作條件查詢時一定要加單引號,不然索引無效。
- 主鍵索引如果沒用到,再查詢for update這種情況,會造成表鎖定。容易造成卡死。
1000000.32 萬
create table sal(t1 float(10,2));
create table sal2(t1 decimal(10,2));
問?在PHP中 ,int 如果是一個有符號數,最大值. int- 4*8=32 2 31 -1
l 表的水平划分
l 垂直分割表
如果你的數據庫的存儲引擎是MyISAM的,則當創建一個表,后三個文件. .frm 記錄表結構. .myd 數據 *.myi 這個是索引.
mysql5.5.19的版本,他的數據庫文件,默認放在 (看 my.ini文件中的配置.)
l 讀寫分離