1. 程式人生 > >資料庫sql優化總結之1-百萬級資料庫優化方案+案例分析

資料庫sql優化總結之1-百萬級資料庫優化方案+案例分析

專案背景

有三張百萬級資料表

知識點表(ex_subject_point)9,316條資料

試題表(ex_question_junior)2,159,519條資料 有45個欄位

知識點試題關係表(ex_question_r_knowledge)3,156,155條資料

測試資料庫為:mysql (5.7)

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

案例分析:

SELECT ex_question_junior.QUESTION_ID 
FROM ex_question_junior 
WHERE ex_question_junior.GRADE_ID=1

    執行時間:17.609s (多次執行,在17s左右徘徊)

  優化後:給GRADE_ID欄位新增索引後

  執行時間為:11.377s(多次執行,在11s左右徘徊)

  備註:我們一般在什麼欄位上建索引?

  這是一個非常複雜的話題,需要對業務及資料充分分析後再能得出結果。主鍵及外來鍵通常都要有索引,其它需要建索引的欄位應滿足以下條件:

    a、欄位出現在查詢條件中,並且查詢條件可以使用索引;

    b、語句執行頻率高,一天會有幾千次以上;

    c、通過欄位條件可篩選的記錄集很小,那資料篩選比例是多少才適合?

  這個沒有固定值,需要根據表資料量來評估,以下是經驗公式,可用於快速評估:

  小表(記錄數小於10000行的表):篩選比例<10%;

  大表:(篩選返回記錄數)<(表總記錄數*單條記錄長度)/10000/16

  單條記錄長度≈欄位平均內容長度之和+欄位數*2

  以下是一些欄位是否需要建B-TREE索引的經驗分類:

2、應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描

select id from t where num is null

最好不要給資料庫留NULL,儘可能的使用 NOT NULL填充資料庫.

備註、描述、評論之類的可以設定為 NULL,其他的,最好不要使用NULL。

不要以為 NULL 不需要空間,比如:char(100) 型,在欄位建立時,空間就固定了, 不管是否插入值(NULL也包含在內),都是佔用 100個字元的空間的,如果是varchar這樣的變長欄位, null 不佔用空間。

可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢:

select id from t where num = 0

案例分析:

在mysql資料庫中對欄位進行null值判斷,是不會放棄使用索引而進行全表掃描的。

SELECT ex_question_junior.QUESTION_ID
FROM ex_question_junior 
WHERE IS_USE is NULL

執行時間是:11.729s

SELECT ex_question_junior.QUESTION_ID
FROM ex_question_junior 
WHERE IS_USE =0

執行時間是12.253s

時間幾乎一樣。

3、應儘量避免在 where 子句中使用 != 或 <> 操作符,否則將引擎放棄使用索引而進行全表掃描。

案例分析:

在mysql資料庫中where 子句中使用 != 或 <> 操作符,引擎不會放棄使用索引。

EXPLAIN
SELECT ex_question_junior.QUESTION_ID
FROM ex_question_junior 
WHERE ex_question_junior.GRADE_ID !=15

執行時間是:17.579s

執行時間是:16.966s

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

案例分析:

GRADE_ID欄位有索引,QUESTION_TYPE沒索引

執行時間是:11.661s

優化方案:

通過union all 方式,把有索引欄位和非索引欄位分開。索引欄位就有效果了

執行時間是:11.811s

但是,非索引欄位依然查詢速度會很慢,所以查詢條件,能加索引的儘量加索引

5.in 和 not in 也要慎用,否則會導致全表掃描

案例分析

注:在mysql資料庫中where 子句中對索引欄位使用 in 和 not in操作符,引擎不會放棄使用索引。

注:在mysql資料庫中where 子句中對不是索引欄位使用 in 和 not in操作符,會導致全表掃描。

案例分析2:

用between和in的區別

SELECT ex_question_junior.QUESTION_ID
FROM ex_question_junior
WHERE ex_question_junior.QUESTION_TYPE  IN(1,2,3,4)

執行時間為1.082s

SELECT ex_question_junior.QUESTION_ID
FROM ex_question_junior
WHERE ex_question_junior.QUESTION_TYPE between 1 and 4

執行時間為0.924s

時間上是相差不多的

案例分析3:

用exists 和 in區別:結論

用exists 和 in區別:結論

1. in()適合B表比A表資料大的情況(A<B)

select * from A

where id in(select id from B)

2. exists()適合B表比A表資料小的情況(A>B)

  select * from A

  where exists(

  select 1 from B where B.id = A.id

  )

3.當A表資料與B表資料一樣大時,in與exists效率差不多,可任選一個使用.語法

select * from A

where id in(select id from B)

ex_question_r_knowledge表資料量大,ex_subject_point表資料量小

****************************************************************************

ex_question_r_knowledge(A)表資料量大,ex_subject_point表資料量小(B)(A>B)

用exists適合

SELECT *
FROM ex_question_r_knowledge
WHERE ex_question_r_knowledge.SUBJECT_POINT_ID IN
(
    SELECT ex_subject_point.SUBJECT_POINT_ID
    FROM ex_subject_point
    WHERE ex_subject_point.SUBJECT_ID=7
)
SELECT *
FROM ex_question_r_knowledge
WHERE  exists
(
    SELECT 1
    FROM ex_subject_point
    WHERE ex_subject_point.SUBJECT_ID=7
    AND ex_subject_point.SUBJECT_POINT_ID = ex_question_r_knowledge.SUBJECT_POINT_ID
)

執行時間是:13.537s

*************************************************************************

ex_subject_point表資料量小(A),ex_question_r_knowledge(B)表資料量大(A<B)

用in適合

SELECT *
 FROM ex_subject_point 
WHERE
 ex_subject_point.SUBJECT_POINT_ID IN( SELECT 
ex_question_r_knowledge.SUBJECT_POINT_ID FROM 
ex_question_r_knowledge WHERE 
ex_question_r_knowledge.GRADE_TYPE=2 )
SELECT * FROM ex_subject_point WHERE
 ex_subject_point.SUBJECT_POINT_ID IN( SELECT 
ex_question_r_knowledge.SUBJECT_POINT_ID FROM 
ex_question_r_knowledge WHERE 
ex_question_r_knowledge.GRADE_TYPE=2 )

執行時間是:1.554s

SELECT *
    FROM ex_subject_point
    WHERE  exists(
    SELECT ex_question_r_knowledge.SUBJECT_POINT_ID
    FROM ex_question_r_knowledge
    WHERE ex_question_r_knowledge.GRADE_TYPE=2
    AND ex_question_r_knowledge.SUBJECT_POINT_ID= ex_subject_point.SUBJECT_POINT_ID
)

執行時間是:11.978s

6、like模糊全匹配也將導致全表掃描

案例分析

EXPLAIN
 SELECT * 
FROM ex_subject_point 
WHERE ex_subject_point.path like "%/11/%"

若要提高效率,可以考慮全文檢索。lucene瞭解一下。或者其他可以提供全文索引的nosql資料庫,比如tt server或MongoDB

還會陸續更新,還有幾個小節。

昨天晚上突發奇想,like 模糊全匹配,會導致全表掃描,那模糊後匹配和模糊前匹配也會是全表掃描嗎?

今天開電腦,做了下測試。結果如下:

like模糊後匹配,不會導致全表掃描

like模糊前匹配,會導致全表掃描

MY SQL的原理就是這樣的,LIKE模糊全匹配會導致索引失效,進行全表掃描;LIKE模糊前匹配也會導致索引失效,進行全表掃描;但是LIKE模糊後匹配,索引就會有效果。

參考:

https://mp.weixin.qq.com/s?__biz=MzIxMjg4NDU1NA==&mid=2247483684&idx=1&sn=f5abc60e696b2063e43cd9ccb40df101&chksm=97be0c01a0c98517029ff9aa280b398ab5c81fa1fcfe0e746222a3bfe75396d9eea1e249af38&mpshare=1&scene=1&srcid=0606XGHeBS4RBZloVv786wBY#rd

***************************************************************************

作者:小虛竹
歡迎任何形式的轉載,但請務必註明出處。
限於本人水平,如果文章和程式碼有表述不當之處,還請不吝賜教。

我不是個偉大的程式設計師,我只是個有著一些優秀習慣的好程式設計師而己

相關推薦

資料庫sql優化總結1-百萬資料庫優化方案+案例分析

專案背景 有三張百萬級資料表 知識點表(ex_subject_point)9,316條資料 試題表(ex_question_junior)2,159,519條資料 有45個欄位 知識點試題關係表(ex_question_r_knowledge)3,156,155條資料

資料庫sql優化總結2-百萬資料庫優化方案+案例分析

專案背景有三張百萬級資料表知識點表(ex_subject_point)9,316條資料試題表(ex_question_junior)2,159,519條資料 有45個欄位知識點試題關係表(ex_question_r_knowledge)3,156,155條資料測試資料庫為:m

資料庫SQL優化總結1- 百萬資料庫優化方案

一、百萬級資料庫優化方案1.對查詢進行優化,要儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t

資料庫SQL優化總結 百萬資料庫面試優化方案

網上關於SQL優化的教程很多,但是比較雜亂。近日有空整理了一下,寫出來跟大家分享一下,其中有錯誤和不足的地方,還請大家糾正補充。 這篇文章我花費了大量的時間查詢資料、修改、排版,希望大家閱讀之後,感覺好的話推薦給更多的人,讓更多的人看到、糾正以及補充。   一、百萬級資料庫優化

資料庫SQL優化總結 百萬資料庫優化方案

網上關於SQL優化的教程很多,但是比較雜亂。近日有空整理了一下,寫出來跟大家分享一下,其中有錯誤和不足的地方,還請大家糾正補充。 這篇文章我花費了大量的時間查詢資料、修改、排版,希望大家閱讀之後,感覺好的話推薦給更多的人,讓更多的人看到、糾正以及補充。 1.對查詢進行

資料庫SQL優化總結百萬資料庫優化方案

網上關於SQL優化的教程很多,但是比較雜亂。近日有空整理了一下,寫出來跟大家分享一下,其中有錯誤和不足的地方,還請大家糾正補充。 這篇文章我花費了大量的時間查詢資料、修改、排版,希望大家閱讀之後,感覺好的話推薦給更多的人,讓更多的人看到、糾正以及補充。 1.對查詢進行優化

sql 百萬資料庫優化方案

2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t where num is null可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢:select id from t where num=0

MySQL百萬資料庫查詢優化技巧

1.對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。 2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如: select id from t where nu

百萬資料庫記錄下的Mysql快速分頁優化例項

百萬級資料庫記錄下的Mysql快速分頁優化例項   MySql 效能到底能有多高?用了php半年多,真正如此深入的去思考這個問題還是從前天開始。有過痛苦有過絕望,到現在充滿信心!MySql 這個資料庫絕對是適合dba級的高手去玩的,一般做一點1萬篇新聞的小

百萬資料庫優化方案

1.對查詢進行優化,要儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。 2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如: select id from t wh

資料庫設計與優化總結1

一、資料庫的設計的幾點措施 1.關聯表的關聯欄位名稱必須相同。 2.欄位的定義的前兩位是表名,第三位是下劃線,保證規範。 3.常用欄位採用固定單詞,如id 4.如果只有一個索引,索引的名字希望和表名相同,如果是多個,那麼就用表明下劃線欄位名。 5.關聯欄位儘可能為數字型別。

百萬資料庫效能優化(一)——建立索引

對查詢進行優化,要儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。 為了能夠使用索引,我們應該避免使用以下查詢方式: 2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表

mysql+SQL資料庫優化和書寫原則,千萬資料庫記錄查詢輕鬆解決

1.對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。 2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描, Sql 程式碼 : select id from

Netty 系列 Netty 百萬推送服務設計要點

Netty 系列之 Netty 百萬級推送服務設計要點 李林鋒 2015 年 1 月 4 日 話題:語言 & 開發架構 1. 背景 1.1. 話題來源 最近很多從事移動網際網路和物聯網開發的同學給我發郵件或者微博私信我,諮詢推送服務相關的問題。問題五花八門,

Netty系列Netty百萬推送服務設計要點-轉載

1. 背景 1.1. 話題來源 最近很多從事移動網際網路和物聯網開發的同學給我發郵件或者微博私信我,諮詢推送服務相關的問題。問題五花八門,在幫助大家答疑解惑的過程中,我也對問題進行了總結,大概可以歸納為如下幾類: Netty是否可以做推送伺服器? 如果使用Netty開

資料庫--SQL語句總結

SQL語句總結 如何用SQL語句新增,刪除和修改資訊 1.刪除 刪除請求的表達和查詢非常類似,我們可以刪除整個元組,但不能只刪除某個屬性上的值.刪除語句是: delete from r; where P; r代表一個關係,p代表一個謂詞,delete語句首先從r 中找出所有使p(t)為真

SQL 注入基礎系列1——猜解資料庫

DVWA.security=low.SQL Injection 後臺查詢語句: //後臺查詢Sql語句是: SELECT first_name, last_name FROM users WHERE user_id = '$id'; //當user_id輸入1時,實際執行的Sql語句是 S

DB2學習總結1)——DB2資料庫基礎入門

DB2的特性 完全Web使能的:可以利用HTTP來發送詢問給伺服器。 高度可縮放和可靠:高負荷時可利用多處理器和大記憶體,可以跨伺服器地分佈資料庫和資料負荷;能夠以最小的資料丟失快速地恢復,提供

PL/SQL學習總結1

PL/SQL是一種面向過程的類似Pascal的語言,是Oracle公司對SQL語言的功能的擴充套件,它是將過程性結構與oracle SQL無縫的整合在一起而產生的一種結構化的強有力的語言,是一種高階資料庫程式設計語言。 1、程式開始

Mysql資料庫的使用總結ERROR 1146 (42S02)

網上查詢解決辦法時,發現也有不少人有這個問題,而按照停止服務再拷貝的方式還是不行(我剛開始也不行,不過後來就好了,怪了,不知道為什麼)。所以這裡再說一種方法。首先在自己的mysql下,建立一個你即將要拷貝的資料庫(資料庫名要一樣,裡面不需要建表),然後將所有的.frm檔案拷貝到你建的資料庫資料夾下,此時再次進