MYSQL千萬級數據量的優化方法積累

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 ‘%李%’若要提高效率,可以考慮全文檢索。

  1. 如果在 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上建了索引也對查詢效率起不了作用。

  1. 索引並不是越多越好,索引固然可 以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因爲 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有 必要。

  2. 應儘可能的避免更新 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.使用基於遊標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。

  1. 與臨時表一樣,遊標並不是不可使 用。對小型數據集使用 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安裝目錄

  1. 啓動 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 索引

  1. create [unique|FULLTEXT] index 索引名 on 表名 (列名…)

  2. 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. 如果字段是字符類型的索引,用作條件查詢時一定要加單引號,不然索引無效。

  1. 主鍵索引如果沒用到,再查詢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文件中的配置.)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章