MySql數據庫優化-匯總


各位,不喜勿噴,和氣生財~

數據庫優化,是一種綜合性的技術,不是通過某一種方式讓數據庫效率提高很多,而是通過各個方面的優化,來是數據庫效率明顯的穩步的提高。

主要包括以下:

1、庫表的設計優化(三種范式)

2、庫表添加合適的索引(普通索引+主鍵索引+唯一索引+全文索引)

3、分表技術-水平分割與垂直分割

4、讀寫分離(add/delete/update與select分開)

5、多用存儲過程和觸發器(模塊化編程)

6、優化MqSql配置(配置最大並發數,調整緩存大小,my.ini)

7、SQL優化與慢查詢

8、定時清楚垃圾數據,定時進行碎片整理(MyISAM

除此之外,還有 MqSql服務器硬件升級

 

以下進行詳細描述

 

題外話:

存儲引擎:

MyISAM: 查詢速度快,插入速度快,但不支持事務,碎片多;

InnoDB :5.5版本后Mysql的默認數據庫,支持事務,支持ACID事務,支持行級鎖定;

Memory :所有數據置於內存中,擁有極高的插入,適合頻繁的數據更新,更新和查詢效率。但是會占用和數據量成正比的內存空間。並且其內容會在Mysql重新啟動時丟失,不需要保存滴;

數據庫三種模式結構/三級模式 

外模式(用戶):用戶所能看到的數據視圖,可通過數據庫操縱語言對數據進行操作;

模式(概念):用戶視圖的最小並集,所有數據的邏輯結構和概念的描述;

內模式(物理):實際存儲組合,內部視圖,是實際物理存儲的抽象;

 

一、庫表設計

良好的數據庫設計,能夠節省數據庫空間,保持數據完整性,方便應用程序的開發;(相反:數據冗余,空間浪費,插入更新繁雜或者異常)

設計數據庫

1、充分了解需求:標識實體(具體存在的對象、東西,名詞),標識實體屬性,標識實體關系

以BBS論壇為例

實體:

用戶(屬性:昵稱,密碼,郵箱,生日,性別,登記,備注,積分,注冊時間)

主貼(屬性:標題,正文,發帖時間,狀態,發帖人,回復數量,點擊數)

回帖(屬性:帖子編號,回帖人,回帖標題,回帖正文,回帖時間,點擊數)

板塊(屬性:板塊名稱,版主,板塊格言,點擊數,發帖數)

 

2、實體關系

一對一,兩個表的主鍵是公共字段

一對多,主鍵與非主鍵之間的關系

多對一,非主鍵與主鍵之間 的關系

多對多,非主鍵與非主鍵之間的關系

 

3、E-R圖,實體-聯系圖(Entity Relationship Diagram),提供了表示實體類型、屬性和聯系的方法,用來描述現實世界的概念模型

*1、創建表時,將實體轉化為表,將屬性轉化為列,唯一標識一行數據的列可為主鍵,無合適字段做主鍵就用自動增加列, 將關系轉化為主外鍵展示實體之間的關系;

*2、表結構規范化-三范式(

1、列的原子性。列不可分解,確保每列都不能再分解成更基本的數據單位;

2、記錄的唯一標識。給記錄增加一個主鍵,非主鍵字段依賴主鍵字段,即表的列中若有重復數據且與主鍵無關,則可拆分表;

3、字段不存在冗余。不存在傳遞依賴,即若表的除主鍵外各個列間有直接關聯,即非主鍵字段一個字段可以推導出另一個字段,則可拆分表

范式舉例:

山東理工,山東淄博;山大,山東濟南;其中山東濟南就可以拆分(第一范式)山東理工,山東,淄博;山大,山東,濟南;

學號-主,姓名;ID,科目,成績,學號,姓名;滿足第二范式;但不滿足第三范式;如果學號非主鍵,則滿足第三范式;

 *但注意,也有第五第六等范式,范式越高表越多,查詢效率一般就會降低,一般第三范式效率最高列。。

反三范式:學號,語文,數學,英語,總成績;總成績字段就是違反第三范式,適當的數據冗余允許,不然就查詢效率低了:select sum(yw+sx+yy) from t_score或單獨建表 學號,總成績;

由此可見,數據庫的性能效率比規范化更重要;

 


二、庫表添加合適的索引

主鍵索引,唯一索引見上述鏈接;

1、主鍵索引,主鍵查詢時默認使用;

2、組合索引,左邊用,右邊不用;

3、模糊查詢,%或者_寫在左邊不會用索引,右邊會用;

4、條件語句中如果有or,or的兩側均為索引才能使用,否則不會使用;

普通索引與組合索引區別:多個普通索引MySQL只用到認為似乎是最有效率的一個單列索引;組合索引為最左前綴,name-age-city建索引,相當於name,age,age-name,city-name;

主鍵索引與唯一索引區別:主鍵執行計划優於唯一,主鍵索引不能為空,僅一個主鍵索引列,主鍵索引更適合自生成不改變的列,主鍵可被其他列引為外鍵;

唯一索引,檢索到一個直接返回;普通索引,檢查是否是全部才返回;

創建索引語法:

create index 索引名稱 on 表明 (字段名)

創建全文索引語法:

CREATE fulltext INDEX 索引名稱 ON 表明 (字段名)

例子:

  1. SELECT * FROM articles   WHERE MATCH (title,body) AGAINST ('database'); 兩個字段的索引:FULLTEXT (title,body)
  2. SELECT * FROM articles WHERE MATCH (tags) AGAINST ('旅游' IN BOOLEAN MODE);IN BOOLEAN MODE是只有含有關鍵字就行,不用在乎位置,是不是起啟位置.

*僅存儲引擎為MyISAM支持全文索引,InnoDB不支持不支持全文索引;

*mysql默認的閥值是50%,當某字段出現次數只有低於50%(停止詞)的才會出現在結果集中;(意思是,全文索引用在海量數據中,不存在高於50%的情況)

*fulltext不支持中文,用Sphinx是一個基於SQL的全文檢索引擎,結合MySQL,PostgreSQL做全文搜索,他可以提供比數據庫本身更專業的搜索功能,使得應用程序更容易實現專業化的全文檢索;

 

三、分表

水平分表:字段不多但是記錄行數超級多,達到千萬級別,經常檢索速度會很慢;按照合理的邏輯去拆分成一個個較小的表,比如按照月份或者類型等待,利於程序簡單實現,同時必須考慮到避免union,否則不如不拆分;

垂直分表:記錄不多但是字段較多或者較長,占用的空間也比較大,檢索需要大量IO,降低性能;拆分時可將較大字段拆分出來,組成一對一的對應關系表;

 

四、讀寫分離

數據庫服務器壓力大時,可以利用主從數據庫,對僅僅需要查詢,且不特別關注失效性的功能,使用從數據庫進行數據的查詢;

 

五、存儲過程與觸發器

存儲過程:可編程的函數,由sql語句和控制結構組成;

sql:需要先編譯后執行;存儲過程:跨平台和應用使用;速度快,減少網絡流量,組件式編程,統一接口參數安全,靈活性差;

#語法
CREATE PROCEDURE 過程名([[IN|OUT|INOUT] 參數名 數據類型[,[IN|OUT|INOUT] 參數名 數據類型…]]) [特性 ...] 過程體
#小示例
CREATE PROCEDURE proc3(IN parameter int)
  BEGIN
    DECLARE var int;
    SET var=parameter+1;
    IF var=0 THEN
      INSERT INTO t VALUES (17);
    END IF ;
    IF parameter=0 THEN
      UPDATE t SET s1=s1+1;
    ELSE
      UPDATE t SET s1=s1+2;
    END IF ;
  END ;

存儲過程內的普通變量

#語法:DECLARE 變量名1[,變量名2...] 數據類型 [默認值];
DECLARE x1 VARCHAR(5) DEFAULT 'outer';  

變量賦值

#語法:SET 變量名 = 變量值 [,變量名= 變量值 ...]
SET x1=x1+1; 

存儲過程中的用戶變量

#用戶變量一般以@開頭
SET @y='Goodbye Cruel World';

參與select/update/where語句

SELECT data1,data2 INTO x1,@y FROM test.table1 LIMIT 1;
update test.table1 set data1=@y;
insert into test.table1 (data1,data2)values(x1,@y);

判斷語句

#IF分支:
IF 條件1 THEN 語句;
ELSEIF 條件2 THEN 語句;
......
ELSE 語句;
END IF;

#CASE分支:
CASE [條件]
WHEN 條件1 THEN 語句1
WHEN 條件2 THEN 語句2  
......
ELSE 語句n
END CASE

循環語句

LOOP循環:
LOOP
語句群
END LOOP

WHILE語句:
WHILE 條件 DO
語句群
END WHILE

REPEAT UNTIL語句:
REPEAT
語句群
UNTIL 條件
END REPEAT 

跳轉或者終止符

ITERATE 語句:  ITERATE只可以出現在LOOP, REPEAT, 和WHILE語句內。ITERATE意思為:“再次循環”   會再次回到label開始位置;
BEGIN
    DECLARE v INT;
    SET v=0;
    LOOP_LABLE:LOOP
      IF v=3 THEN
        SET v=v+1;
        ITERATE LOOP_LABLE;
      END IF;
      INSERT INTO t VALUES(v);
      SET v=v+1;
      IF v>=5 THEN
        LEAVE LOOP_LABLE;
      END IF;
    END LOOP;
  END;

LEAVE語句:這個語句被用來退出任何被標注的流程控制構造。它和BEGIN ... END或循環一起被使用,像其他語言中的break。

開始結束符

[begin_label:] BEGIN
語句群
END [end_label]

 

 

七、SQL優化與慢查詢

切入點:一個較大的項目,我們想了解當前mysql的運行狀態、是否有耗時較長的sql執行等待

1、數據庫的增刪改查

一般情況下,增刪改總計占數據庫的10%,而90%是查詢操作;

2、show status的相關常用命令

#查看數據庫的一些狀態
show status;
#顯示執行了多少條/次的增刪改查
show stauts like 'com_select';
show stauts like 'com_insert';
show stauts like 'com_delete';
show stauts like 'com_update';
#[session|global] 默認是session會話級-只取出當前窗口的執行;global-從mysql啟動到現在 
show global stauts like 'com_select';

#查詢當前MySQL本次啟動后的運行統計時間(單位:秒)-另外,存儲引擎為MyISAM,且運行時間過長,則注意碎片整理
show status like 'uptime';
#查看試圖連接到MySQL(不管是否連接成功)的連接數
show status like 'connections';
#查看線程緩存內的線程的數量。
show status like 'threads_cached';

#慢查詢
#查看查詢時間超過long_query_time秒的查詢的個數-即慢查詢
show status like 'slow_queries';
#可以顯示當前慢查詢時間(單位:秒)(默認10秒)
show variables like 'long_query_time'; 
#可以修改慢查詢時間(單位:秒)
set long_query_time=1;

  

3、啟動MqSql使用記錄慢查詢日志(2種)

#第一種:中括號[]內的部分是可選的,file_name表示日志文件路徑
#在5.5及以上版本的MySQL中,使用如下命令啟動:
mysqld --safe-mode --show-query-log[=1] [--show-query-log-file=file_name]
#在5.0、5.1等低版本的MySQL中,使用如下命令啟動:
mysqld --log-slow-queries[=file_name]

#第二種:啟動命令配置到my.ini中的[mysqld]節點
[mysqld]
#設置慢查詢界定時間為1秒
long_query_time=1
#5.0、5.1等版本配置如下選項
log-slow-queries="mysql_slow_query.log"
#5.5及以上版本配置如下選項
slow-query-log=On
slow_query_log_file="mysql_slow_query.log"

 重啟mysql

  停止net stop mysql    啟動 net start mysql

 

4、explain

explain命令,可以用顯示mysql如何使用索引來處理select語句以及連接表; 

上述圖片中的字段再次描述:

id:查詢序號,即執行順序號,不重要;

select_type:simple 它表示簡單的select,沒有union和子查詢;primary 最外面的select,在有子查詢的語句中,最外面的select查詢就是primary;union union語句的第二個或者說是后面那一個;

table:顯示這一行的數據是關於哪張表的;

possible_keys:可能會使用的索引;

key:實際使用的索引;優化where語句,選擇合適的字段或者表字段;

key_len:索引長度,越短越好;

ref:使用某個庫表字段 去 匹配表中數據

rows:查詢的行數,越小越好;

extra:關於mysql如何解析查詢的額外信息

  關注當內容顯示using temporary,即需要優化sql,因為用到了緩存;--盡力用小表驅動大表

  舉例:聯表排序:驅動表字段排序直接是驅動表排序/非驅動表排序則先合並結果集后排序(指定聯接條件時滿足查詢條件較少數據表為驅動表,不指定聯接條件時表數據較少的為驅動表

type:重要,連接類型:

  const 表示:表中最多有一個匹配行,且用到了primary key 或者unique索引;

  eq_ref 表示:和前邊表查詢匹配的值,后邊表中最多僅有一個匹配行,且都用到了primary key 或者unique索引,且是最好的表之間的聯接類型

  ref 表示:和前邊表匹配的值,后邊表均會取出,且基於的關鍵字段是索引字段,但不是后邊表的primary key 或者unique索引,則為ref,且是較好的表之間的聯接類型

 

 

 

八、碎片整理

存儲引擎為MyISAM

數據insert會使用其占用空間增加,但delete數據不會是其占用的空間減少,原因:刪除數據時,mysql並不會回收被已刪除數據的占據的存儲空間以及索引位;而是等待新的數據來彌補這個空缺;

語法命令(定期optimize):

#刪除數據后的優化 - 碎片整理
optimize table 表名

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM