百萬級資料庫SQL優化大總結

来源:https://www.cnblogs.com/canfengfeixue/archive/2018/01/03/8185784.html
-Advertisement-
Play Games

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


網上關於SQL優化的教程很多,但是比較雜亂。近日有空整理了一下,寫出來跟大家分享一下,其中有錯誤和不足的地方,還請大家糾正補充。

這篇文章我花費了大量的時間查找資料、修改、排版,希望大家閱讀之後,感覺好的話推薦給更多的人,讓更多的人看到、糾正及補充。

 

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


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


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

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

select id from t where num=10 or Name = 'admin'

可以這樣查詢:

select id from t where num = 10
union all
select id from t where Name = 'admin'


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

select id from t where num in(1,2,3)

對於連續的數值,能用 between 就不要用 in 了:

select id from t where num between 1 and 3

很多時候用 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)

 

6.下麵的查詢也將導致全表掃描:

select id from t where name like ‘%abc%’

若要提高效率,可以考慮全文檢索。

7.如果在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變數,但優化程式不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然 而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下麵語句將進行全表掃描:

select id from t where num = @num

可以改為強制查詢使用索引:

select id from t with(index(索引名)) where num = @num

.應儘量避免在 where 子句中對欄位進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:

select id from t where num/2 = 100

應改為:

select id from t where num = 100*2


9.應儘量避免在where子句中對欄位進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:

select id from t where substring(name,1,3) = ’abc’       -–name以abc開頭的id
select id from t where datediff(day,createdate,’2005-11-30′) = 0    -–‘2005-11-30’    --生成的id

應改為:

select id from t where name like 'abc%'
select id from t where createdate >= '2005-11-30' and createdate < '2005-12-1'


10.不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。

11.在使用索引欄位作為條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應儘可能的讓欄位順序與索引順序相一致。

12.不要寫一些沒有意義的查詢,如需要生成一個空表結構:

select col1,col2 into #t from t where 1=0

這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:
create table #t(…)

13.Update 語句,如果只更改1、2個欄位,不要Update全部欄位,否則頻繁調用會引起明顯的性能消耗,同時帶來大量日誌。

14.對於多張大數據量(這裡幾百條就算大了)的表JOIN,要先分頁再JOIN,否則邏輯讀會很高,性能很差。

15.select count(*) from table;這樣不帶任何條件的count會引起全表掃描,並且沒有任何業務意義,是一定要杜絕的。


16.索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有 必要。

17.應儘可能的避免更新 clustered 索引數據列,因為 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引數據列,那麼需要考慮是否應將該索引建為 clustered 索引。

18.儘量使用數字型欄位,若只含數值信息的欄位儘量不要設計為字元型,這會降低查詢和連接的性能,並會增加存儲開銷。這是因為引擎在處理查詢和連 接時會逐個比較字元串中每一個字元,而對於數字型而言只需要比較一次就夠了。

19.儘可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長欄位存儲空間小,可以節省存儲空間,其次對於查詢來說,在一個相對較小的欄位內搜索效率顯然要高些。

20.任何地方都不要使用 select * from t ,用具體的欄位列表代替“*”,不要返回用不到的任何欄位。

21.儘量使用表變數來代替臨時表。如果表變數包含大量數據,請註意索引非常有限(只有主鍵索引)。

22. 避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。臨時表並不是不可使用,適當地使用它們可以使某些常式更有效,例如,當需要重覆引用大型表或常用表中的某個數據集時。但是,對於一次性事件, 最好使用導出表。

23.在新建臨時表時,如果一次性插入數據量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然後insert。

24.如果使用到了臨時表,在存儲過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。

25.儘量避免使用游標,因為游標的效率較差,如果游標操作的數據超過1萬行,那麼就應該考慮改寫。

26.使用基於游標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。

27.與臨時表一樣,游標並不是不可使用。對小型數據集使用 FAST_FORWARD 游標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括“合計”的常式通常要比使用游標執行的速度快。如果開發時 間允許,基於游標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。

28.在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句後向客戶端發送 DONE_IN_PROC 消息。

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

30.儘量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。

 

實際案例分析:拆分大的 DELETE 或INSERT 語句,批量提交SQL語句
  如果你需要在一個線上的網站上去執行一個大的 DELETE 或 INSERT 查詢,你需要非常小心,要避免你的操作讓你的整個網站停止相應。因為這兩個操作是會鎖表的,表一鎖住了,別的操作都進不來了。
  Apache 會有很多的子進程或線程。所以,其工作起來相當有效率,而我們的伺服器也不希望有太多的子進程,線程和資料庫鏈接,這是極大的占伺服器資源的事情,尤其是記憶體。
  如果你把你的表鎖上一段時間,比如30秒鐘,那麼對於一個有很高訪問量的站點來說,這30秒所積累的訪問進程/線程,資料庫鏈接,打開的文件數,可能不僅僅會讓你的WEB服務崩潰,還可能會讓你的整台伺服器馬上掛了。
  所以,如果你有一個大的處理,你一定把其拆分,使用 LIMIT oracle(rownum),sqlserver(top)條件是一個好的方法。下麵是一個mysql示例:

複製代碼
while(1){

   //每次只做1000條

   mysql_query(“delete from logs where log_date <= ’2012-11-01’ limit 1000”);

   if(mysql_affected_rows() == 0){
     //刪除完成,退出!      break;   } //每次暫停一段時間,釋放表讓其他進程/線程訪問。 usleep(50000) }
複製代碼

 

當你想要跑到夢想的終點時,誰也無法阻擋你的腳步!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在向伺服器拷貝文件的時候卡死,直接任務管理器結束應用程式,但是隨之引發一個問題,就是之後不能從本地向伺服器拷貝文件了,只能伺服器自己複製粘貼。 解決辦法重啟rdpclip.exe,先在任務管理器中結束rdpclip.exe 進程,然後重新運行(開始->運行->rdpclip.exe ),解決問題。 ...
  • 上次介紹了ES集群搭建的方法,希望能幫助大家,這兒我再接著介紹kafka集群,接著上次搭建的效果。 首先我們來簡單瞭解下什麼是kafka和zookeeper? Apache kafka 是一個分散式的基於push-subscribe的消息系統,它具備快速、可擴展、可持久化的特點。它現在是Apache ...
  • 一個正常的UAC設備插入Android 7.0是預設打開UAC配置的,列印的log如下: 而Android4.0是沒有預設打開,是需要進行相應的配置的;這裡可以看到其驅動程式為snd-usb-audio,依據這個關鍵詞在內核中查找到如下內容: 需要在 /kernel/arch/arm/configs ...
  • 大家好,我是豹哥,獵豹的豹,犀利哥的哥。今天豹哥給大家講的是 嵌入式開發里的source文件 。 眾所周知,嵌入式開發屬於偏底層的開發,主要編程語言是C和彙編。所以本文要講的source文件主要指的就是c文件和彙編文件。 儘管在平常開發中,我們都只會關註自己創建的.c/.h/.s源文件,但實際上我們 ...
  • 說明 由於大部分VPN被封,翻牆過程中無意間接觸到了VPS(Virtual Private Server 虛擬專用伺服器,可用於翻牆),所以簡單記錄下VPS服務搭建流程。 此教程基於centos7,本人選擇使用阿裡雲伺服器(香港區域,可訪問外網)進行搭建。 安裝組件 安裝python組件:yum i ...
  • 1 停止nexus服務 [root@node001 bin]# /usr/local/nexus/nexus-2.14.5-02/bin/nexus stop****************************************WARNING - NOT RECOMMENDED TO RU ...
  • linux 內核版本 2.6.27.29 /* * linux/arch/arm/kernel/head.S * Kernel startup code for all 32-bit CPUs */ #include <linux/linkage.h> #include <linux/init.h> ...
  • 今天又是SQL Server... 其實這兩天寫SQL已經寫的很煩了,但是沒辦法,要交實驗報告。。。 其實覺得老師也是在偷懶,這題和後面的連續幾題都差不多了,基本上就是先存一張臨時表的套路,不然總是報那個某某欄位不存在或沒有包含在聚合函數中balabala…… 基本上都是這樣了,按上面說的套路來,沒 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...