MySQL的20條基本優化 加參考資料

来源:http://www.cnblogs.com/yuanpengchao/archive/2016/08/17/5778753.html
-Advertisement-
Play Games

mysql的性能優化包羅甚廣:索引優化,查詢優化,查詢緩存,伺服器設置優化,操作系統和硬體優化,應用層面優化(web伺服器,緩存)等等。這裡的記錄的優化技巧更適用於開發人員,都是從網路上收集和自己整理的,主要是查詢語句上面的優化,其它層面的優化技巧在此不做記錄。查詢的開銷指標:執行時間檢查的行數返回 ...


mysql的性能優化包羅甚廣:
索引優化,查詢優化,查詢緩存,伺服器設置優化,操作系統和硬體優化,應用層面優化(web伺服器,緩存)等等。這裡的記錄的優化技巧更適用於開發人員,都是從網路上收集和自己整理的,主要是查詢語句上面的優化,其它層面的優化技巧在此不做記錄。
查詢的開銷指標:
執行時間
檢查的行數
返回的行數
建立索引的幾個準則:
1、合理的建立索引能夠加速數據讀取效率,不合理的建立索引反而會拖慢資料庫的響應速度。
2、索引越多,更新數據的速度越慢。
3、儘量在採用MyIsam作為引擎的時候使用索引(因為MySQL以BTree存儲索引),而不是InnoDB。但MyISAM不支持Transcation。
4、當你的程式和資料庫結構/SQL語句已經優化到無法優化的程度,而程式瓶頸並不能順利解決,那就是應該考慮使用諸如memcached這樣的分散式緩存系統的時候了。
5、習慣和強迫自己用EXPLAIN來分析你SQL語句的性能。
1. count的優化
比如:計算id大於5的城市

1 a. select count(*) from world.city where id > 5;
2 b. select (select count(*) from world.city) – count(*) from world.city where id <= 5;


a語句當行數超過11行的時候需要掃描的行數比b語句要多, b語句掃描了6行,此種情況下,b語句比a語句更有效率。當沒有where語句的時候直接

select count(*) from world.city

這樣會更快,因為mysql總是知道表的行數。
2. 避免使用不相容的數據類型。
例如float和int、char和varchar、binary和varbinary是不相容的。數據類型的不相容可能使優化器無法執行一些本來可以進行的優化操作。
在程式中,保證在實現功能的基礎上,儘量減少對資料庫的訪問次數;通過搜索參數,儘量減少對錶的訪問行數,最小化結果集,從而減輕網路負擔;能夠分開的操作儘量分開處理,提高每次的響應速度;在數據視窗使用SQL時,儘量把使用的索引放在選擇的首列;演算法的結構儘量簡單;在查詢時,不要過多地使用通配符如 SELECT * FROM T1語句,要用到幾列就選擇幾列如:SELECT COL1,COL2 FROM T1;在可能的情況下儘量限制儘量結果集行數如:SELECT TOP 300 COL1,COL2,COL3 FROM T1,因為某些情況下用戶是不需要那麼多的數據的。不要在應用中使用資料庫游標,游標是非常有用的工具,但比使用常規的、面向集的SQL語句需要更大的開銷;按照特定順序提取數據的查找。
3. 索引欄位上進行運算會使索引失效。
儘量避免在WHERE子句中對欄位進行函數或表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:

SELECT * FROM T1 WHERE F1/2=100 應改為: SELECT * FROM T1 WHERE F1=100*2


4. 避免使用!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN等這樣的操作符.
因為這會使系統無法使用索引,而只能直接搜索表中的數據。例如: SELECT id FROM employee WHERE id != “B%” 優化器將無法通過索引來確定將要命中的行數,因此需要搜索該表的所有行。在in語句中能用exists語句代替的就用exists.
5. 儘量使用數字型欄位.
一部分開發人員和資料庫管理人員喜歡把包含數值信息的欄位
設計為字元型,這會降低查詢和連接的性能,並會增加存儲開銷。這是因為引擎在處理查詢和連接回逐個比較字元串中每一個字元,而對於數字型而言只需要比較一次就夠了。
6. 合理使用EXISTS,NOT EXISTS子句。如下所示:

1.SELECT SUM(T1.C1) FROM T1 WHERE (SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0)
2.SELECT SUM(T1.C1) FROM T1WHERE EXISTS(SELECT * FROM T2 WHERE T2.C2=T1.C2)


兩者產生相同的結果,但是後者的效率顯然要高於前者。因為後者不會產生大量鎖定的表掃描或是索引掃描。如果你想校驗表裡是否存在某條紀錄,不要用count(*)那樣效率很低,而且浪費伺服器資源。可以用EXISTS代替。如:

IF (SELECT COUNT(*) FROM table_name WHERE column_name = ‘xxx’)

可以寫成:

IF EXISTS (SELECT * FROM table_name WHERE column_name = ‘xxx’)


7. 能夠用BETWEEN的就不要用IN
8. 能夠用DISTINCT的就不用GROUP BY
9. 儘量不要用SELECT INTO語句。SELECT INTO 語句會導致表鎖定,阻止其他用戶訪問該表。
10. 必要時強制查詢優化器使用某個索引

SELECT * FROM T1 WHERE nextprocess = 1 AND processid IN (8,32,45) 改成:
SELECT * FROM T1 (INDEX = IX_ProcessID) WHERE nextprocess = 1 AND processid IN (8,32,45)


則查詢優化器將會強行利用索引IX_ProcessID 執行查詢。
11. 消除對大型表行數據的順序存取
儘管在所有的檢查列上都有索引,但某些形式的WHERE子句強迫優化器使用順序存取。如:

SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008


解決辦法可以使用並集來避免順序存取:

SELECT * FROM orders WHERE customer_num=104 AND order_num>1001 UNION SELECT * FROM orders WHERE order_num=1008


這樣就能利用索引路徑處理查詢。【jacking 數據結果集很多,但查詢條件限定後結果集不大的情況下,後面的語句快】
12. 儘量避免在索引過的字元數據中,使用非打頭字母搜索。這也使得引擎無法利用索引。
見如下例子:

SELECT * FROM T1 WHERE NAME LIKE%L%SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’
SELECT * FROM T1 WHERE NAME LIKE ‘L%

 


即使NAME欄位建有索引,前兩個查詢依然無法利用索引完成加快操作,引擎不得不對全表所有數據逐條操作來完成任務。而第三個查詢能夠使用索引來加快操作,不要習慣性的使用 ‘%L%’這種方式(會導致全表掃描),如果可以使用`L%’相對來說更好;
13. 雖然UPDATE、DELETE語句的寫法基本固定,但是還是對UPDATE語句給點建議:

a) 儘量不要修改主鍵欄位。
b) 當修改VARCHAR型欄位時,儘量使用相同長度內容的值代替。
c) 儘量最小化對於含有UPDATE觸發器的表的UPDATE操作。
d) 避免UPDATE將要複製到其他資料庫的列。
e) 避免UPDATE建有很多索引的列。
f) 避免UPDATE在WHERE子句條件中的列。

14. 能用UNION ALL就不要用UNION
UNION ALL不執行SELECT DISTINCT函數,這樣就會減少很多不必要的資源
在跨多個不同的資料庫時使用UNION是一個有趣的優化方法,UNION從兩個互不關聯的表中返回數據,這就意味著不會出現重覆的行,同時也必須對數據進行排序,我們知道排序是非常耗費資源的,特別是對大表的排序。
UNION ALL可以大大加快速度,如果你已經知道你的數據不會包括重覆行,或者你不在乎是否會出現重覆的行,在這兩種情況下使用UNION ALL更適合。此外,還可以在應用程式邏輯中採用某些方法避免出現重覆的行,這樣UNION ALL和UNION返回的結果都是一樣的,但UNION ALL不會進行排序。
15. 欄位數據類型優化:
a. 避免使用NULL類型:NULL對於大多數資料庫都需要特殊處理,MySQL也不例外,它需要更多的代碼,更多的檢查和特殊的索引邏輯,有些開發人員完全沒有意識到,創建表時NULL是預設值,但大多數時候應該使用NOT NULL,或者使用一個特殊的值,如0,-1作為預設值。
b. 儘可能使用更小的欄位,MySQL從磁碟讀取數據後是存儲到記憶體中的,然後使用cpu周期和磁碟I/O讀取它,這意味著越小的數據類型占用的空間越小,從磁碟讀或打包到記憶體的效率都更好,但也不要太過執著減小數據類型,要是以後應用程式發生什麼變化就沒有空間了。修改表將需要重構,間接地可能引起代碼的改變,這是很頭疼的問題,因此需要找到一個平衡點。
c. 優先使用定長型
16. 關於大數據量limit分佈的優化見下麵鏈接(當偏移量特別大時,limit效率會非常低):
http://ariyue.iteye.com/blog/553541
附上一個提高limit效率的簡單技巧,在覆蓋索引(覆蓋索引用通俗的話講就是在select的時候只用去讀取索引而取得數據,無需進行二次select相關表)上進行偏移,而不是對全行數據進行偏移。可以將從覆蓋索引上提取出來的數據和全行數據進行聯接,然後取得需要的列,會更有效率,看看下麵的查詢:
mysql> select film_id, description from sakila.film order by title limit 50, 5;
如果表非常大,這個查詢最好寫成下麵的樣子:

mysql> select film.film_id, film.description from sakila.film
inner join(select film_id from sakila.film order by title liimit 50,5) as film usinig(film_id);

 


17. 程式中如果一次性對同一個表插入多條數據,比如以下語句:

insert into person(name,age) values(‘xboy’, 14);
insert into person(name,age) values(‘xgirl’, 15);
insert into person(name,age) values(‘nia’, 19);

 


把它拼成一條語句執行效率會更高.

insert into person(name,age) values(‘xboy’, 14), (‘xgirl’, 15),(‘nia’, 19);

 


18. 不要在選擇的欄位上放置索引,這是無意義的。應該在條件選擇的語句上合理的放置索引,比如where,order by。

SELECT id,title,content,cat_id FROM article WHERE cat_id = 1;

 


上面這個語句,你在id/title/content上放置索引是毫無意義的,對這個語句沒有任何優化作用。但是如果你在外鍵cat_id上放置一個索引,那作用就相當大了。
19. ORDER BY語句的MySQL優化:
a. ORDER BY + LIMIT組合的索引優化。如果一個SQL語句形如:

SELECT [column1],[column2],…. FROM [TABLE] ORDER BY [sort] LIMIT [offset],[LIMIT];

 


這個SQL語句優化比較簡單,在[sort]這個欄位上建立索引即可。
b. WHERE + ORDER BY + LIMIT組合的索引優化,形如:

SELECT [column1],[column2],…. FROM [TABLE] WHERE [columnX] = [VALUE] ORDER BY [sort] LIMIT [offset],[LIMIT];

 


這個語句,如果你仍然採用第一個例子中建立索引的方法,雖然可以用到索引,但是效率不高。更高效的方法是建立一個聯合索引(columnX,sort)
c. WHERE + IN + ORDER BY + LIMIT組合的索引優化,形如:

SELECT [column1],[column2],…. FROM [TABLE] WHERE [columnX] IN ([value1],[value2],…) ORDER BY [sort] LIMIT [offset],[LIMIT];

 


這個語句如果你採用第二個例子中建立索引的方法,會得不到預期的效果(僅在[sort]上是using index,WHERE那裡是using where;using filesort),理由是這裡對應columnX的值對應多個。
目前哥還木有找到比較優秀的辦法,等待高手指教。
d.WHERE+ORDER BY多個欄位+LIMIT,比如:
SELECT * FROM [table] WHERE uid=1 ORDER x,y LIMIT 0,10;
對於這個語句,大家可能是加一個這樣的索引:(x,y,uid)。但實際上更好的效果是(uid,x,y)。這是由MySQL處理排序的機製造成的。
20. 其它技巧:
http://www.cnblogs.com/nokiaguy/archive/2008/05/24/1206469.html
http://www.cnblogs.com/suchshow/archive/2011/12/15/2289182.html
http://www.cnblogs.com/cy163/archive/2009/05/28/1491473.html
http://www.cnblogs.com/younggun/articles/1719943.html
http://wenku.baidu.com/view/f57c7041be1e650e52ea9985.html
最後,你可以使用explain關鍵字去判斷和評測一個sql語句是否還有優化的可能性,關於它的詳細使用請參考mysql手冊


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

-Advertisement-
Play Games
更多相關文章
  • 查看MySQL二進位文件中的內容有兩種方式 1. mysqlbinlog 2. SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count] 下麵來測試一下,在mysql中執行如下操作 對應二進位日誌中的內容如下 ...
  • 從MySQL 5.5遷移到Mariadb 10.1.14 遷移計劃如下: 1.備份MySQL 5.5的資料庫,對指定庫進行備份。 2.還原到Mariadb,然後建立複製。 3.然後就可以願意啥時候切換就啥時候切換。 遇到的問題: 因為一般都是innodb,所以我想用xtrabackup工具備份。備份 ...
  • 1.NoSql簡介 NoSql(Not Only Sql)指的是非關係型的資料庫。下一代資料庫主要解決幾個要點:非關係型的、分散式的、開源的、水平可擴展的。原始的目的是為了大規模web應用,這場 運動開始於2009年初,通常特性應用如:模式自由、支持簡易複製、簡單的API、最終的一致性(非ACID) ...
  • http://btmiller.com/2015/04/13/get-list-of-keys-from-dictionary-in-python-2-and-3.html Get a List of Keys From a Dictionary in Both Python 2 and Pytho ...
  • SQL Server分頁查詢幾種方式介紹 0. 序言 1. TOP…NOT IN… 2. ROW_NUMBER() 3. OFFSET…FETCH 4. 執行計劃 5. 補充 ...
  • http://askubuntu.com/questions/656610/trying-to-install-mysql-connector-for-python-3?rq=1 trying to install mysql-connector for python 3 trying to ins ...
  • http://stackoverflow.com/questions/4960048/python-3-and-mysql http://stackoverflow.com/questions/4960048/python-3-and-mysql up vote61down votefavorite ...
  • 上一章給大家說的是資料庫的視圖,存儲過程等等操作,這章主要講索引,以及索引註意事項,如果想看前面的文章,url如下: MYSQL入門全套(第一部) MYSQL入門全套(第二部) 索引簡介 索引是對資料庫表中一個或多個列(例如,employee 表的姓名 (name) 列)的值進行排序的結構。如果想按 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...