SQL優化二

創建適當的索引     

提及提升數據庫性能,索引是最物美價廉的東西了。不用加內存,不用改程序,不用調sql,只要執行個正確的'create index',查詢速度就可能提升百倍千倍,這可真有誘惑力。但是天下沒有免費的午飯,查詢速度的提升是以插入、更新、刪除的速度爲代價的,這些寫操做,增長了大量的I/O。mysql

是否是創建一個索引就能解決全部的問題?ename上沒有創建索引會怎樣?程序員

UPDATE emp set ename='zhangsan' where empno=100002;
select * from emp where ename='zhangsan';

我emp表中有2446297條記錄,empno建立索引前,執行查詢花了16秒鐘,進行了全表掃描算法

explain SELECT * from emp where empno=100002;

---測試案例命令以下 (最好以 select * from emp e,dept d where e.empno=123451 )sql

*添加主鍵數據庫

ALTER TABLE emp ADD PRIMARY KEY(empno);

再執行查詢,執行時間顯示0,用explain分析安全

*刪除主鍵app

alter table emp drop primary key;

索引的原理說明     

沒有索引爲何會慢?性能

使用索引爲何會快?測試

btree類型的索引,就是使用的二分查找法,確定快啊,算法複雜度是log2N,也就是說16條數據查4次,32條數據查5次,64條數據查6次....依次類推。優化

使用索引跟沒使用索引的區別,就跟咱們使用新華字典查字,一個是根據拼音或者筆畫查找,一個是從頭至尾一頁一頁翻。

索引的代價

一、磁盤佔用

二、對dml(update delete insert)語句的效率影響

btree 方式檢索,算法複雜度: log2N 次數

 

哪些列上適合添加索引       

一、較頻繁的做爲查詢條件字段應該建立索引

select * from emp where empno = 1;

二、惟一性太差的字段不適合單首創建索引,即便頻繁做爲查詢條件

   select * from emp where sex = '男'

三、更新很是頻繁的字段不適合建立索引

select * from emp where logincount = 1

四、不會出如今WHERE子句中的字段不應建立索引

索引的類型             

  • 主鍵索引,主鍵自動的爲主索引 (類型Primary)
  • 惟一索引 (UNIQUE)
  • 普通索引 (INDEX)
  • 全文索引 (FULLTEXT) [適用於MyISAM] ——》sphinx + 中文分詞    coreseek [sphinx 的中文版 ]
  • 綜合使用=>複合索引

簡述mysql四種索引的區別

PRIMARY 索引 =》在主鍵上自動建立

UNIQUE 索引=> 只要是UNiQUE 就是Unique索引.(只能在字段內容不重複的狀況下,才能建立惟一索引)

INDEX 索引=>就是普通索引

FULLTEXT => 只在MYISAM 存儲引擎支持, 目的是全文索引,在內容系統中用的多, 在全英文網站用多(英文詞獨立). 中文數據不經常使用,意義不大,國內全文索引一般使用 sphinx來完成,全文索引只能在 char varchar text字段建立.

全文索引案例

1.建立表

create table news(id int , title varchar(32),con varchar(1024)) engine=MyISAM;

2.創建全文索引

create fulltext index ful_inx on news (con);

3.插入數據

這裏要注意,對於常見的英文 fulltext 不會匹配,並且插入的語句自己是正確的.

'but it often happens that they are not above supporting themselves by dishonest means.which should be more disreputable.Cultivate poverty like a garden herb'

4.看看匹配度

 
mysql> select match(con) against('poverty') from news;

+-------------------------------+

| match(con) against('poverty') |

+-------------------------------+

|                             0 |

|                             0 |

|                             0 |

|            0.9853024482727051 |

+-------------------------------+
 

0表示沒有匹配到,或者你的詞是中止詞,是不會創建索引的.

使用全文索引,不能使用like語句,這樣就不會使用到全文索引了.

複合索引

create index 索引名 on 表名(列1,列2);

索引的使用             

創建索引

create [UNIQUE|FULLTEXT]  index index_name on tbl_name (col_name [(length)] [ASC | DESC] , …..);
alter table table_name ADD INDEX [index_name]  (index_col_name,...)

添加主鍵(索引) ALTER TABLE 表名 ADD PRIMARY KEY(列名,..); 聯合主鍵

刪除索引

DROP INDEX index_name ON tbl_name;
alter table table_name drop index index_name;

刪除主鍵(索引)比較特別: alter table t_b drop primary key;

查詢索引(都可)

show index(es) from table_name;
show keys from table_name;
desc table_Name;

修改索引,咱們通常是先刪除再從新建立.

查詢要使用索引最重要的條件是查詢條件中須要使用索引。

下列幾種狀況下有可能使用到索引:
1,對於建立的多列索引,只要查詢條件使用了最左邊的列,索引通常就會被使用。
2,對於使用like的查詢,查詢若是是  '%aaa' 不會使用到索引, 'aaa%' 會使用到索引。

下列的表將不使用索引:
1,若是條件中有or,即便其中有條件帶索引也不會使用。
2,對於多列索引,不是使用的第一部分,則不會使用索引。
3,like查詢是以%開頭
4,若是列類型是字符串,那必定要在條件中將數據使用引號引用起來。不然不使用索引。(添加時,字符串必須'')
5,若是mysql估計使用全表掃描要比使用索引快,則不使用索引。

測試案例(就在前面的dept表上作演示.)

CREATE TABLE dept(
deptno MEDIUMINT   UNSIGNED  NOT NULL  DEFAULT 0,
dname VARCHAR(20)  NOT NULL  DEFAULT "",
loc VARCHAR(13) NOT NULL DEFAULT ""
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

--放入數據,前面應該已經添加了,若是沒有則須要從新添加

--測試開始.

添加一個主鍵索引

alter table dept add primary key (deptno)

--測試語句

explain select * from dept where deptno=1;

結果是:

 
mysql> explain select * from dept where deptno=1;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: dept
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 3
          ref: const
         rows: 1
        Extra:
1 row in set (0.00 sec)
 

--建立多列索引

alter table dept add index myind (dname,loc);

--證實對於建立的多列索引,只要查詢條件使用了最左邊的列,索引通常就會被使用

explain select * from dept where dname='研發部'; 會顯示使用到了索引myind

explain select * from dept where loc='MsBDpMRX'; 不會顯示使用到了索引myind

--對於使用like的查詢

explain select * from dept where dname like '%研發部'; 不會顯示使用到了索引myind

explain select * from dept where dname like '研發部%'; 會顯示使用到了索引myind

--若是條件中有or,即便其中有條件帶索引也不會使用

--爲了演示,咱們把複合索引刪除,而後只在dname上加入索引.

alter table dept drop index myind
alter table dept add index myind (dname)
explain select * from dept where dname='研發部' or loc='aa';-- 就不會使用到dname列上的

--若是列類型是字符串,那必定要在條件中將數據使用引號引用起來。不然不使用索引

select * from dept from dname=1234; //不會使用到索引

select * from dept from dname='1234'; //會使用到索引

查看索引的使用狀況
show status like 'Handler_read%';
你們能夠注意:
handler_read_key:這個值越高越好,越高表示使用索引查詢到的次數。

handler_read_rnd_next:這個值越高,說明查詢低效。

* 這時咱們會看到handler_read_rnd_next值很高,爲何,這是由於咱們前面沒有加索引的時候,作過屢次查詢的緣由.

經常使用SQL優化            

大批量插入數據(MySql管理員) 瞭解
對於MyISAM:

alter table table_name disable keys;
loading data//insert語句;
alter table table_name enable keys;

對於Innodb:
1,將要導入的數據按照主鍵排序
2,set unique_checks=0,關閉惟一性校驗。
3,set autocommit=0,關閉自動提交。

優化group by 語句
默認狀況,MySQL對全部的group by col1,col2進行排序。這與在查詢中指定order by col1, col2相似。若是查詢中包括group by但用戶想要避免排序結果的消耗,則可使用order by null禁止排序

有些狀況下,可使用鏈接來替代子查詢。
由於使用join,MySQL不須要在內存中建立臨時表。(講解)

若是想要在含有or的查詢語句中利用索引,則or之間的每一個條件列都必須用到索引,若是沒有索引,則應該考慮增長索引(與環境相關 講解)

 select * from 表名 where 條件1='' or 條件2='tt'

explain select * from dept group by dname; =>這時顯示 extra: using filesort 說明會進行排序

explain select * from dept group by dname order by null =>這時不含有顯示 extra: using filesort 說明不會進行排序

***有些狀況下,可使用鏈接來替代子查詢。由於使用join,MySQL不須要在內存中建立臨時表。

explain select * from emp , dept where emp.deptno=dept.deptno;

和下面比較就能夠說明問題!!

explain select * from emp left join dept on emp.deptno=dept.deptno;

選擇合適的存儲引擎           

MyISAM:Mysql5.5默認的MySQL存儲引擎。若是應用是以讀操做和插入操做爲主,只有不多的更新和刪除操做,而且對事務的完整性要求不是很高。其優點是訪問的速度快。

InnoDB:Mysql5.6默認的MySQL存儲引擎,提供了具備提交、回滾和崩潰恢復能力的事務安全。可是對比MyISAM,寫的處理效率差一些而且會佔用更多的磁盤空間。

Memory:數據存在內存中,服務重啓時,數據丟失

MyISAM: 在插入數據時,默認放在最後. ,刪除數據後,空間不回收.(不支持事務和外鍵)

InnoDB 支持事務和外鍵

對應咱們程序員說,經常使用的存儲引擎主要是 myisam / innodb / memory,heap 表

若是選用小原則:

1.若是追求速度,不在意數據是否一直保存,也不考慮事務,請選擇 memory 好比存放用戶在線狀態.

2.若是表的數據要持久保存,應用是以讀操做和插入操做爲主,只有不多的更新和刪除操做,而且對事務的完整性要求不是很高。選用MyISAM

3.若是須要數據持久保存,並提供了具備提交、回滾和崩潰恢復能力的事務安全,請選用Innodb

選擇合適的數據類型           

在精度要求高的應用中,建議使用定點數來存儲數值,以保證結果的準確性。能用deciaml就不要用float

對於存儲引擎是MyISAM的數據庫,若是常常作刪除和修改記錄的操做,要定時執行optimize table table_name;功能對錶進行碎片整理。

日期類型要根據實際須要選擇可以知足應用的最小存儲的早期類型

create table bbs(id int ,con varchar(1024) , pub_time int);

date('Ymd',時間-3*24*60*60); 2038年-1-19

對於使用浮點數和定點數的案例說明

create table temp1( t1 float(10,2), t2 decimal(10,2));

insert into temp1 values(1000000.32,1000000,32); 發現 t1 成了 1000000.31 因此有問題.

對於optimize table 表名 演示

create table temp2( id int) engine=MyISAM;
insert into temp2 values(1); insert into temp2 values(2); insert into temp2 values(3);
insert into temp2 select * from temp2;--複製
delete from temp2 where id=1; --發現該表對應的數據文件沒有變小

按期執行 optimize table temp2 發現表大小變化,碎片整理完畢

對於InnoDB它的數據會存在data/ibdata1目錄下,在data/數據庫/只有一個 *.frm表結構文件.

相關文章
相關標籤/搜索