索引、視圖、SQL優化以及數據庫存儲過程

 

一.索引

索引是查詢優化最有效和最常用的技術

索引是對數據庫表中一個列或多個列進行排序的結構。

索引是一個單獨的、物理的數據庫結構,它是指向表中某一列或若干列上的指針列表。

mysql中,一個表的物理存儲由兩部分組成,一部分用於存放表的數據,另一部分存放索引,當進行數據搜索時,mysql會首先搜索索引,從中找到所需數據的起始位置的指針,再直接通過指針查找目標數據。

1.創建索引:

CREATE INDEX 索引名 on 表名(要添加索引的列名)

可以給一個表中的多個列添加索引

通過在查詢sql語句前加一句Explain可以分析索引效率,

有這樣一張表:

執行EXPLAIN SELECT*FROM t_product WHERE productName ='電視機'

 

 

同一條sql查詢語句,在沒建立索引時,可以看到掃描了9

 

CREATE INDEX index_pname ON t_product(productName)

在建立索引之後,再次執行相同查詢語句,發現只掃描了1行便得到了結果

效果如下圖

 

 

 

 

2.刪除索引:

Alter table 表名 drop index 索引名

 

如何選擇索引列:

   1.Where子句中常出現的列

select id from t_student where sName=’張三’

   2.在join子句中常出現的列

select s.*,g.grade from t_student s join t_grade g on s.id=g.studentId

   3.頻繁進行排序或者分組的列

select s.*,g.grade from t_student s join t_grade g on s.id=g.studentId  group by s.name order by g.grade

 

like使用索引列,like比較特別,mysql對其索引的情況是:操作數不以通配符開頭。

 

select*from t_student where sName like ‘j%’  會使用索引

 

select*from t_student where sName like ‘%j%’  不會使用索引,仍會全表查詢

 

 

索引的缺點:

  1. 減慢增刪改數據的速度
  2. 佔用磁盤空間
  3. 增加查詢優化器負擔

不能簡單的認爲“索引越多,性能越高”,不必對每個數據列都進行索引。如果很少使用或從不使用某個索引,建議刪除該索引。

 

 

二.視圖

視圖是數據庫中由一個或多個基本表導出的虛擬表。

視圖是指計算機數據庫中的視圖,是一個虛擬表,其內容由查詢定義。 

  1.創建視圖

CREATE VIEW v_find AS SELECT id,productName,price,imgPath FROM t_product;

  2.使用視圖

直接從視圖中查詢

SELECT*FROM v_find;

 

對於複雜的連表查詢,可以利用創建視圖來使SQL語句變得簡單。

CREATE VIEW v_join AS SELECT r.address,r.price,m.manName FROM test.t_man m,test.t_room r WHERE r.manId=m.id;

SELECT*FROM v_join where manName=’張三

  3.刪除視圖

DROP VIEW v_find

 

注意:視圖只適用於查詢,它只是一張虛擬表!如果需要添加數據,那麼必須加在真實表中。

 

.SQL語句優化策略

1.  給適當的列加上索引。

 

2.  儘量避免全表掃描,首先應考慮在where及order by涉及的列上建立索引。

 

 

3.  避免select *

   從數據庫裏讀出越多的數據,那麼查詢就會變得越慢

 

4.  永遠爲每張表設置一個ID

   使用VARCHAR類型來當主鍵會使得性能下降

 

5.  使用EMUM而不是VARCHAR

sex  ENUM(‘’男,’女’)

如果一個列只含有有限樹木的特定值,比如:性別、狀態等,儘量採用ENUM列舉出所有可能的取值作爲數據類型,enum列的值都是以標識數值標識,mysql會處理的更快。

 

6.  儘量避免在where子句中使用or來連接條件,如果一個字段有索引,一個字段沒有索引,將導致引擎放棄使用索引而進行全表掃描

 

7.  模糊查詢不要以通配符開始,否則會導致索引失效而進行全表掃描

select *from t_student where sName like ‘a%’

 

8.  儘量避免在where子句中對字段進行表達式操作,這會導致引擎失效放棄使用索引而進行全表掃描。

         select id from t where num/2=100

         應該改爲 select id from t where num=100*2

 

         9.  In和not  in要慎用,否則可以導致全表掃描,可以用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)

 

10.一個表的索引最好不要超過6個,若太多則應考慮刪除一些不常使用的索引

 

11.儘量避免大事務操作,提高系統併發能力

 

12.並不是所有索引對查詢都有效,當索引列有大量數據重複時,SQL查詢可能不會去利用索引,如果一表中有字段sex,male,female幾乎各一半,那麼即使在sex上建了索引頁會查詢效率起不了太大作用

 

 

 

 

四、數據庫存儲過程

l  什麼是存儲過程?

存儲過程是一段寫好的SQL代碼,它是存在數據庫的目錄中,外部程序可以直接調用數據庫裏面定義好的存儲過程。

l  存儲過程的優點

  1. 性能上的提高,比起通過應用程序發送SQL語句給數據庫執行,讓數據庫自己內部執行存儲過程效率更高、速度更快。
  2. 減少了應用程序與數據庫信息的交互頻率。在一些業務中,應用程序發送多條SQL指令給服務器。而使用存儲過程則只需要一條調用存儲過程的語句,然後獲取需要的數據就可以了。
  3. 存儲過程重用性比較高,保存在數據庫裏面所以對任何應來說都可以使用。
  4. 存儲過程是一種安全的做法,數據庫管理員可以對那些沒有權限訪問數據庫中的表格的應用,給他們使用存儲過程的權限來獲得數據服務。

l  存儲過程的缺點

  1. 存儲過程會使得數據庫佔用的系統資源加大。
  2. 因爲存儲過程依舊是sql,沒辦法像編程語言那樣寫出複雜業務邏輯對應的存儲過程。
  3. 存儲過程不容易進行調試
  4. 存儲過程是寫及維護難度都比較大。

 

l  存儲過程語法

#創建存儲過程

DELIMITER//

CREATE PROCEDURE p_find()

BEGIN

         SELECT* FROM test.t_man;

END;

//

#使用存儲過程

         CALL P_find();

#刪除存儲過程

         DROP PROCEDURE p_find;

l  存儲過程參數

         #IN表示輸入參數,OUT表示輸出參數

DELIMITER//

CREATE PROCEDURE pro(IN  mname  VARCHAR(20),OUT  jname  VARCHAR(20))

BEGIN

         SELECT *FROM test.t_man where manName=mname;

END;

//

CALL pro(‘張三’,@j);

SELECT @j;

l  存儲過程定義變量

DECLARE t INT DEFAULT 0;

SET t=10;

SET t=t+1;

注意:存儲過程只能在存儲過程的開始定義

實例:

#在exercise數據庫中有t_man表,包含字段員工名稱,員工職位名稱。輸入一個公民姓名,根據職位名稱,判斷出所屬等級(表中沒有等級)

DELIMITER//

CREATE PROCEDURE p_get(IN mname VARCHAR(20),OUT info VARCHAR(20))

BEGIN     

         #定義變量

         DECLARE mjob VARCHAR(20) DEFAULT '';

         #查詢指定姓名的員工的職務,並將職務賦值給mjob變量

         SELECT job INTO mjob FROM exercise.t_man WHERE manName=mname;

        

         IF mjob='經理' OR mjob='助理' THEN

                   SET info='高管';

         ELSEIF mjob='會計' OR mjob='文員' THEN

                   SET info ='行政人員';

         ELSE

                   SET info='辦事人員';

         END IF;

END

//

#兩句可以一起執行,但是中間必須用”;”隔開

CALL p_get('張三丰',@m);

         SELECT @m;

 

 

 

#動態條件查詢

DELIMITER//

CREATE PROCEDURE p_dyna(IN mname VARCHAR(20),IN startDate DATE,IN endDate DATE)

BEGIN

         DECLARE msql VARCHAR(200) DEFAULT 'select *from exercise.t_man where 1=1 ';

         IF mname IS NOT NULL AND mname !='' THEN

                   SET msql=CONCAT(msql,"and manName like '",mname,"%' ");

         END IF;

         IF startDate IS NOT NULL THEN

                   SET msql=CONCAT(msql,"and birthday>='",startDate,"' ");

         END IF;

         IF endDate IS NOT NULL THEN

                   SET msql=CONCAT(msql,"and birthday<='",endDate,"'");

         END IF;

         #執行SQL語句,首先建一個全局變量

         SET @ms=msql;

         PREPARE st FROM @ms;

         EXECUTE st;

         DEALLOCATE PREPARE st;

END;

//

CALL p_dyna('張','1980-01-01','2016-01-01')

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