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

1.對查詢進行優化,應儘可能避免全表掃描,首先應考慮在 where 及 order by 涉及的列上創建索引。php

2.應儘可能避免在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描,如:select id from t where num is null能夠在num上設置默認值0,確保表中num列沒有null值,而後這樣查詢:select id from t where num=0mysql

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=20sql

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%’bash

10.不要在 where 子句中的「=」左邊進行函數、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引。session

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.儘可能避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。

====================================

一、分庫分表 
很明顯,一個主表(也就是很重要的表,例如用戶表)無限制的增加勢必嚴重影響性能,分庫與分表是一個很不錯的解決途徑,也就是性能優化途徑,如今的案例是咱們有一個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

二、不停機修改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中看到的數字根本不能做爲條件來查詢

三、經常使用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文件中的配置.)

l 讀寫分離

相關文章
相關標籤/搜索