[精華摘要] DBA專家門診一期:索引與sql優化

1、索引我通常都是隻有主鍵,這玩意兒,是否是越少越好?

答:mysql

在平常的業務開發中,常見使用到索引的地方大概有兩類:
(1)作業務約束需求,好比須要保證表中每行的單個字段或者某幾個組合字段是惟一的,則能夠在表中建立惟一索引
(2)提升SQL語句執行速度,能夠根據SQL語句的查詢條件在表中建立合適的索引,以此來提高SQL語句的執行速度程序員

2、我有一個問題想問問,如今在作一個與圖書有關的項目,其中有一個功能是按圖書書名搜索類似圖書列表,問題不難,可是想優化一下,有以下問題想請教一下:

一、在圖書數據庫數據表的書名字段裏,按圖書書名進行關鍵字搜索,如何快速搜索相關的圖書? 如今因爲數據很少,直接用的like模糊查找驗證功能而已;
二、如何按匹配的關鍵度進行快速排序?好比搜索「算法」,有一本書是《算法》,另外一本書是《算法設計》,要求前者排在更前面。如今的排序是根據數據表中的主鍵序號id進行的排序,沒有達到想要的效果。算法

答:sql

一、若是數據量不大,是能夠在數據庫中完成搜索的,能夠在搜索字段上建立索引,而後進行搜索查詢:
CREATE TABLE `book` (  
  `book_id` int(11) NOT NULL AUTO_INCREMENT,  
  `book_name` varchar(100) NOT NULL,  
  .............................  
  PRIMARY KEY (`book_id`),  
  KEY `ind_name` (`book_name`)  
) ENGINE=InnoDB  
select book.*  from book , (select book_id from book where book_name like '%算法%')  book_search_id  where book.book_id=book_search_id.book_id;
可是當數據量變得很大後,就不在適合了,能夠採用一些其餘的第三方搜索技術好比sphinx。

二、select book_id,book_name from book_search where book_name like '%算%' order by book_name;  
+---------+--------------+  
| book_id | book_name    |  
+---------+--------------+  
|       2 | 算法       |  
|       1 | 算法設計 |

3、請教一下有關模糊查詢的優化,有沒有什麼比較成熟的好的策略?

答:數據庫

模糊查詢分爲半模糊和全模糊,也就是:oracle

select * from book where name like 'xxx%';(半模糊)  
select * from book where name like '%xxx%';(全模糊)

半模糊能夠可使用到索引,全模糊在上面場景是不能使用到索引的,但能夠進行一些改進,好比:函數

select book.*  from book , (select book_id from book where book_name like '%算法%')  book_search_id where book.book_id=book_search_id.book_id;

注意這裏book_id是主鍵,同時在book_name上建立了索引
上面的sql語句能夠利用全索引掃描來完成優化,可是性能不會太好;特別在數據量大,請求頻繁的業務場景下不要在數據庫進行模糊查詢;非得使用數據庫的話 ,建議不要在生產庫進行查詢,能夠在只讀節點進行查詢,避免查詢形成主業務數據庫的資源消耗完,致使故障. 可使用一些開源的搜索引擎技術,好比sphinx.oop

4、可貴大師出現。我想問下,sql優化通常從那幾個方面入手?多表之間的鏈接方式:Nested Loops,Hash Join 和 Sort Merge Join,是否是Hash Join最優鏈接?

答:性能

SQL優化須要瞭解優化器原理,索引的原理,表的存儲結構,執行計劃等,能夠買一本書來系統的進行學習,多多實驗;不一樣的數據庫優化器的模型不同,好比oracle支持NL,HJ,SMJ,可是mysql只支持NL,不通的鏈接方式適用於不一樣的應用場景;
NL:對於被鏈接的數據子集較小的狀況,嵌套循環鏈接是個較好的選擇
HJ:對於列鏈接是作大數據集鏈接時的經常使用方式
SMJ:一般狀況下散列鏈接的效果都比排序合併鏈接要好,然而若是行源已經被排過序,在執行排序合併鏈接時不須要再排序了,這時排序合併鏈接的性能會優於散列鏈接。學習

5、有個問題:分類表TQueCategory,問題表TQuestion(T-SQL)

CREATE TABLE TQueCategory  
(  
ID INT IDENTITY(1,1) PRIMARY KEY,        --問題分類ID  
NAME VARCHAR(20)        --問題分類名稱  
)  
CREATE TABLE TQuestion  
(  
ID INT IDENTITY(1,1) PRIMARY KEY,        --問題ID  
CateID INT NOT NULL,        --問題分類ID  
TITLE VARCHAR(50),        --問題標題  
CONTENT VARCHAR(500)        --問題內容  
)

當前要統計某個分類下的問題數,有兩種方式:
1.每次統計,在TQuestion經過CateID進行分組統計
SELECT CateID,COUNT(1) AS QueNum FROM TQuestion GROUP BY CateID WHERE 1=1
2.在TQueCategory表增長字段QueNum,用於標識該分類下的問題數量
ALTER TABLE TQueCategory ADD QueNum INT
SELECT CateID,QueNum FROM TQueCategory
問:在哪一種業務應用場景下采用上面哪一種方式性能比較好,爲何?

答:

方案 一 須要對 TQuestion 的 CateID字段 進行分組 ,能夠在CateID上建立一個索引,這樣就能夠索引掃描來完成查詢;
方案 二 須要對 TQueCategory 進行掃描就能夠得出結果,可是必須在問題表有插入,刪除的時候維護quenum數量;
分析:
單單從SQL的性能來看,分類表的數量應該是遠遠小於問題表的數量的,因此方案二的性能會比較好; 可是若是TQuestion 的插入很是頻繁的話,會帶來對TQueCategory的頻繁更新,一次TQuestion 的insert或deleted就會帶來一次TQueCategory 的update,這個代價實際上是蠻高的; 若是這個分類統計的查詢不是很是頻繁的話,建議仍是使用方案一; 同時還可能還會其餘的業務邏輯統計需求(例如:CateID +時間),這個時候在把邏輯放到TQueCategory就不合適了。

6、分頁該怎麼優化才行?

答:

普通寫法:
select * from t where sellerid=100 limit 100000,20
普通limit M,N的翻頁寫法,每每在越日後翻頁的過程當中速度越慢,緣由
mysql會讀取表中的前M+N條數據,M越大,性能就越差。

優化寫法:

select t1.* from  t t1,(select id from t where sellerid=100 limit 100000,20) t2 where t1.id=t2.id;

優化後的翻頁寫法,先查詢翻頁中須要的N條數據的主鍵id,在根據主鍵id回表查詢所須要的N條數據,此過程當中查詢N條數據的主鍵ID在索引中完成
注意:須要在t表的sellerid字段上建立索引

create index ind_sellerid on t(sellerid);

案例:
慢查詢:

select id, ... from t_buyer where sellerId = 765922982 and  
gmt_modified >= '1970-01-01 08:00:00' and gmt_modified <= '2013-06-05 17:11:31'   
limit 255000, 5000;
5000 rows in set (90 sec)

優化後:

selectt2.* from 
(select id from t_buyer where sellerId = 765922982 and
andgmt_modified >= '1970-01-01 08:00:00' and
andgmt_modified <= '2013-06-05 17:11:31'   
limit 255000, 5000)t1,t_buyer t2 where t1.id=t2.id  
index:seller_id,gmt_modified
5000 rows in set (4.25 sec)

7、能夠詳細說明一下「最後建議不要在數據庫中使用外鍵,讓應用程序來保證。」的緣由嗎?咱們公司在項目中常用外鍵,用程序來保證不是相對而言更加複雜了嗎?

答:

這裏的不建議使用外鍵,主要考慮到 :
第一.維護成本上,把一些業務邏輯交由數據庫來保證,當業務需求發生改動的時候,須要同時考慮應用程序和數據庫,有時候一些數據庫變動或者bug,可能會致使外鍵的失效;同時也給數據庫的管理人員帶來維護的麻煩,不便於管理。
第二.性能上考慮,當大量數據寫入的時候,外鍵確定會帶來必定的性能損耗,當出現這樣的問題時候,再來改造去除外鍵,真的就不值得了;
最後,不在數據庫中參與業務的計算(存儲過程,函數,觸發器,外鍵),是保證數據庫運行穩定的一個好的最佳實踐。

8、mysql如何查詢須要優化的語句,好比慢查詢的步奏,如何找出須要通知程序員修改或者優化的sql語句,如何快速找到mysql瓶頸?

答:

1.能夠將mysql的慢日誌打開,就能夠記錄執行時間超過指定閥值的慢SQL到本地文件或者數據庫的slow_log表中;在RDS中默認是打開了慢日誌功能的:long_query_time=1,表示會記錄執行時間>=1秒的慢sql;

2.如何快速找到mysql瓶頸:簡單一點的方法,能夠經過監控mysql所在主機的性能(CPU,IO,load等),以及mysql自己的一些狀態值(connections,thread running,qps,命中率等;RDS提供了完善的數據庫監控體系,包括了CPU,IOPS,Disk,Connections,QPS,能夠重點關注cpu,IO,connections,disk 4個 指標; cpu,io,connections主要體如今了性能瓶頸,disk主要體現了空間瓶頸; 有時候一條慢sql語句的頻繁調用,也可能致使整個實例的cpu,io,connections達到100%;也有可能一條排序的sql語句,消耗大量的臨時空間,致使實例的空間消耗完。

相關文章
相關標籤/搜索