當前位置:首頁 » 編程語言 » mysqlsql執行優化
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

mysqlsql執行優化

發布時間: 2023-04-19 07:54:21

A. mysql資料庫怎麼優化sql語句

一、MySQL資料庫有幾個配置選項可以幫助我們及時捕獲低效SQL語句

1,slow_query_log
這個參數設置為ON,可以捕獲執行時間超過一定數值的SQL語句。

2,long_query_time
當SQL語句執行時間超過此數值時,就會被記錄到日誌中,建議設置為1或者更短。

3,slow_query_log_file
記錄日誌的文件名。

4,log_queries_not_using_indexes
這個參數設置為ON,可以捕獲到所有未使用索引的SQL語句,盡管這個SQL語句有可能執行得挺快。

二、檢測mysql中sql語句的效率的方法

1、通過查詢日誌
(1)、Windows下開啟MySQL慢查詢
MySQL在Windows系統中的配置文件一般是是my.ini找到[mysqld]下面加上
代碼如下
log-slow-queries = F:/MySQL/log/mysqlslowquery。log
long_query_time = 2

(2)、Linux下啟用MySQL慢查詢
MySQL在Windows系統中的配置文件一般是是my.cnf找到[mysqld]下面加上
代碼如下
log-slow-queries=/data/mysqldata/slowquery。log
long_query_time=2

B. mysql 優化sql方法有哪些

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

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

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

4.應盡量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20

5.下面的查詢也將導致全表掃描:
select id from t where name like '%abc%'
若要提高效率,可以考慮全文檢索。

6.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

7.如果在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變數,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:
select id from t where num=@num
可以改為強制查詢使用索引:
select id from t with(index(索引名)) where num=@num

8.應盡量避免在 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.很多時候用 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)

14.並不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,如一表中有欄位sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。

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

C. mysql 存儲過程執行太慢怎麼優化

1.當我們請求mysql伺服器的時候,MySQL前端會有一個監聽,請求到了之後,伺服器得到相關的SQL語句,執行之前(虛線部分為執行),還會做許可權的判斷
2.通過許可權之後,SQL就到MySQL內部,他會在查詢緩存中,看該SQL有沒有執行過,如果有查詢過,則把緩存結果返回,說明在MySQL內部,也有一個查詢緩存.但是這個查詢緩存,默認是不開啟的,這個查詢緩存,和我們的Hibernate,Mybatis的查詢緩存是一樣的,因為查詢緩存要求SQL和參數都要一樣,所以這個命中率是非常低的(沒什麼卵用的意思)。
3.如果我們沒有開啟查詢緩存,或者緩存中沒有找到對應的結果,那麼就到了解析器,解析器主要對SQL語法進行解析
4.解析結束後就變成一顆解析樹,這個解析樹其實在Hibernate裡面也是有的,大家回憶一下,在以前做過Hibernate項目的時候,是不是有個一個antlr.jar。這個就是專門做語法解析的工具.因為在Hibernate裡面有HQL,它就是通過這個工具轉換成SQL的,我們編程語言之所以有很多規范、語法,其實就是為了便於這個解析器解析,這個學過編譯原理的應該知道.
5.得到解析樹之後,不能馬上執行,這還需要對這棵樹進行預處理,也就是說,這棵樹,我沒有經過任何優化的樹,預處理器會這這棵樹進行一些預處理,比如常量放在什麼地方,如果有計算的東西,把計算的結果算出來等等...
6.預處理完畢之後,此時得到一棵比較規范的樹,這棵樹就是要拿去馬上做執行的樹,比起之前的那棵樹,這棵得到了一些優化
7.查詢優化器,是MySQL裡面最關鍵的東西,我們寫任何一條SQL,比如SELECT * FROM USER WHERE USERNAME = toby AND PASSWORD = 1,它會怎麼去執行?它是先執行username = toby還是password = 1?每一條SQL的執行順序查詢優化器就是根據MySQL對數據統計表的一些信息,比如索引,比如表一共有多少數據,MySQL都是有緩存起來的,在真正執行SQL之前,他會根據自己的這些數據,進行一個綜合的判定,判斷這一次在多種執行方式裡面,到底選哪一種執行方式,可能運行的最快.這一步是MySQL性能中,最關鍵的核心點,也是我們的優化原則.我們平時所講的優化SQL,其實說白了,就是想讓查詢優化器,按照我們的想法,幫我們選擇最優的執行方案,因為我們比MySQL更懂我們的數據.MySQL看數據,僅僅只是自己收集到的信息,這些信息可能是不準確的,MySQL根據這些信息選了一個它自認為最優的方案,但是這個方案可能和我們想像的不一樣.
8.這里的查詢執行計劃,也就是MySQL查詢中的執行計劃,比如要先執行username = toby還是password = 1
9.這個執行計劃會傳給查詢執行引擎,執行引擎選擇存儲引擎來執行這一份傳過來的計劃,到磁碟中的文件中去查詢,這個時候重點來了,影響這個查詢性能最根本的原因是什麼?就是硬碟的機械運動,也就是我們平時熟悉的IO,所以一條查詢語句是快還是慢,就是根據這個時間的IO來確定的.那怎麼執行IO又是什麼來確定的?就是傳過來的這一份執行計劃.(優化就是制定一個我們認為最快的執行方案,最節省IO,和執行最快)
10.如果開了查詢緩存,則返回結果給客戶端,並且查詢緩存也放一份。

D. mysql的sql語句優化5種方式

只有5種嗎?我知道十種以上的說。

  1. 索引(沒我得全表查詢了)

  2. 改變數據儲引擎(MyISAM沒事務再也不用擔心鎖表了)

  3. 增加冗餘數來減少連表查詢數(消耗硬碟空間減少CPU使用)

  4. 調整查詢順序減少查詢量優先(數量少了連表的笛卡兒積也少了)

  5. 全文索引(文字長度有限制,而且IO使用量會大增,但是妥妥的快)

  6. 查詢盡量不要用函數(函數可是不走索引的哦親)

  7. 查詢變數類型要提前對好減少系統負擔(我提前改變了系統你就不用檢測了)

  8. 升級伺服器硬體(沒什麼是氪金解決不了的)

  9. 配置好臨時表空間,合理理由臨時表減少主表查詢搶資源(唯我獨查)

  10. 合理理由函數減少系統的判斷(明明都能確認內容不同你用UNION 系統還是傻傻的查一遍是否重復UNION ALL則跳過這個步驟同理 inner join 和 left join 也一樣)

  11. 強制走索引(復合索引的情況有時候手動走比系統判斷要好哦)

  12. 臟讀、幻讀等(你堵車我繞路)

  13. 數據歸檔,遷移(沒用的數據要進倉哦,別占著主表的資源)

  14. 表的碎片整理(遷移後碎片整理更健康哦親)

  15. 索引重構(數據都走了索引也應該重構一下才能保證速度哦)

  16. 善用存儲過程(串N個表(N大於10)的查詢千萬別一個SQL到底,分布式查詢在吧結果集合並吧騷年)

  17. 預處理數據(mysql也有job哦,對於經常要子查詢的數據可以先弄個明細表根據主表在後台進行補完,查詢的時候就更方便了)

  18. 懶得說了。。。。。。。。。。。。。。。。。。

E. 關於優化mysql中的sql語句

character introcer翻譯過來就是字元引導。也就是針對字元串,顯式的給定一個字元編碼和排序規則,不受系統參數的影響。

總結 Introcer 使用規則:


1. convert 函數

convert 函數類似於 introcer,不過只能指定字元集。

2. charset 函數

檢測字元串的字元集。可以檢測出當前字元串在當前 session 的字元集。

3. set names 語句

語法為:

SETNAMES{'charset_name'[COLLATE 'collation_name'] | DEFAULT}

這條語句最常用,可是也最容易被濫用,比如語句:

  • set names latin1 collate latin1_bin;


  • 執行後會默認執行一系列語句,也就是把非服務端的相關參數給重新設定了。

  • 4. set character set 語句語法為:

  • SET{CHARACTERSET|CHARSET}{'charset_name' | DEFAULT}


  • 類似語句 set names,同樣是設置以下三個 session 參數:

  • character_set_results

  • character_set_client

  • character_set_connection

  • 同樣是可以恢復默認值,還有同樣的限制規則等。不過有兩點不同:1)參數 character_set_connection 的值不會被設定為指定的字元集,而是繼承參數 character_set_database 所設定的字元集。

    5. collate 子句

    collate 語句強制指定排序規則,優先順序最高。也就是顯式指定 collate 會覆蓋已有的排序規則。

    這里涉及到單個字元串以及字元串拼接的排序規則問題。

F. MySQL——SQL優化

優化的目的就是讓sql語句使用索引,避免進行全文檢索,以此加速檢索的速度。在使用mysql的過程中,我們接觸最多的就是sql語句了。這是最容易優化也是最常優化的地方。

SQL優化有以下幾點:

explain模擬優化器執行SQL語句,在5.6以及以後的版本中,除過select,其他比如insert,update和delete均可以使用explain查看執行計劃,從而知道mysql是如何處理sql語句,分析查詢語句或者表結構的性能瓶頸。

explain的作用

G. mysql SQL語句優化

語句基本上沒什麼可優化的,最多就是查詢條件的引號要取消,例如:
select * from aa where 編號=指定編號

你的主索引,是PRIMARY KEY吧,唯一、非空,這已經是最高級別的索引了,資料庫也沒有再次優化的餘地

剩下可做的事情就是資料庫系統優化,例如改變索引緩沖區長度(key_buffer)
一般,該變數控制緩沖區的長度在處理索引表(讀/寫操作)時使用。MySQL使用手冊指出該變數可以不斷增加以確保索引表的最佳性能,並推薦使用與系統內存25%的大小作為該變數的值。這是MySQL十分重要的配置變數之一,如果你對優化和提高系統性能有興趣,可以從改變 key_buffer_size變數的值開始。

如果MYISAM引擎,可以考慮使用myisamchk -r進行修復,例如:
myisamchk --sort_buffer_size=16M --key_buffer_size=16M --read_buffer_size=1M --write_buffer_size=1M -r aa

H. Mysql SQL優化之 limit offset 很大時性能降低

Mysql SQL優化之 limit offset 很大時性能降低(InnoDB引擎)

在 mysql 中,如果select時 offset 很大, 即使相關索引建的挺好, 也會悔閉造成慢查詢.
如:

索引只能找到主鍵,要取其他欄位,還要用主鍵逐個查表,判斷條件並排序,然後拋棄 offset 個, 留下 offset+1 到 offset+limit 個. 時間被花在了用主鍵逐個查表取別的欄位那慶返里了譽前飢.
如果能在找主鍵的時候就拋棄不需要的行,然後需要其他欄位的時候再按主鍵取,就能避免逐條按主鍵取其他欄位的 IO 時間, 從而提高性能.

https://www.jb51.net/article/141933.htm

I. MySQL中如何查看「慢查詢」,如何分析執行SQL的效率

一、MySQL資料庫有幾個配置選項可以幫助我們及時捕獲低效SQL語句x0dx0ax0dx0a1,slow_query_logx0dx0a這個參數設置為ON,可以捕獲執行時間超過一定數值的SQL語句。x0dx0ax0dx0a2,long_query_timex0dx0a當SQL語句執行時間超過此數值時,就會被記錄到日誌中,建議設置為1或者更短。x0dx0ax0dx0a3,slow_query_log_filex0dx0a記錄日誌的文件名。x0dx0ax0dx0a4,log_queries_not_using_indexesx0dx0a這個參數設置為ON,可以捕獲到所有未使用索引的SQL語句,盡管這個SQL語句有可能執行得挺快。x0dx0ax0dx0a二、檢測mysql中sql語句的效率的方法x0dx0ax0dx0a1、通過查詢日誌x0dx0a(1)、Windows下開啟MySQL慢查詢x0dx0aMySQL在Windows系統中的配置文件一般是是my.ini找到[mysqld]下面加上x0dx0a代碼如下x0dx0alog-slow-queries = F:/MySQL/log/mysqlslowquery。logx0dx0along_query_time = 2x0dx0ax0dx0a(2)、Linux下啟用MySQL慢查詢x0dx0aMySQL在Windows系統中的配置文件一般是是my.cnf找到[mysqld]下面加上x0dx0a代碼如下x0dx0alog-slow-queries=/data/mysqldata/slowquery。logx0dx0along_query_time=2x0dx0a說明x0dx0alog-slow-queries = F:/MySQL/log/mysqlslowquery。x0dx0a為慢查詢日誌存放的位置,一般這個目錄要有MySQL的運行帳號的可寫許可權,一般都將這個目錄設置為MySQL的數據存放目錄;x0dx0along_query_time=2中的2表示查詢超過兩秒才記錄;x0dx0ax0dx0a2.show processlist 命令x0dx0ax0dx0aSHOW PROCESSLIST顯示哪些線程正在運行。您也可以使用mysqladmin processlist語句得到此信息。x0dx0a各列的含義和用途:x0dx0aID列x0dx0a一個標識,你要kill一個語句的時候很有用,用命令殺掉此查詢 /*/mysqladmin kill 進程號。x0dx0auser列x0dx0a顯示單前用戶,如果不是root,這個命令就只顯示你許可權范圍內的sql語句。x0dx0ahost列x0dx0a顯示這個語句是從哪個ip的哪個埠上發出的。用於追蹤出問題語句的用戶。x0dx0adb列x0dx0a顯示這個進程目前連接的是哪個資料庫。x0dx0acommand列x0dx0a顯示當前連接的執行的命令,一般就是休眠(sleep),查詢(query),連接(connect)。x0dx0atime列x0dx0a此這個狀態持續的時間,單位是秒。x0dx0astate列x0dx0a顯示使用當前連接的sql語句的狀態,很重要的列,後續會有所有的狀態的描述,請注意,state只是語句執行中的某一個狀態,一個 sql語句,以查詢為例,可能需要經過ing to tmp table,Sorting result,Sending data等狀態才可以完成x0dx0ainfo列x0dx0a顯示這個sql語句,因為長度有限,所以長的sql語句就顯示不全,但是一個判斷問題語句的重要依據。x0dx0ax0dx0a這個命令中最關鍵的就是state列,mysql列出的狀態主要有以下幾種:x0dx0aChecking tablex0dx0a正在檢查數據表(這是自動的)。x0dx0aClosing tablesx0dx0a正在將表中修改的數據刷新到磁碟中,同時正在關閉已經用完的表。這是一個很快的操作,如果不是這樣的話,就應該確認磁碟空間是否已經滿了或者磁碟是否正處於重負中。x0dx0aConnect Outx0dx0a復制從伺服器正在連接主伺服器。x0dx0ax0dx0aCopying to tmp table on diskx0dx0a由於臨時結果集大於tmp_table_size,正在將臨時表從內存存儲轉為磁碟存儲以此節省內存。x0dx0aCreating tmp tablex0dx0a正在創建臨時表以存放部分查詢結果。x0dx0adeleting from main tablex0dx0a伺服器正在執行多表刪除中的第一部分,剛刪除第一個表。x0dx0adeleting from reference tablesx0dx0a伺服器正在執行多表刪除中的第二部分,正在刪除其他表的記錄。x0dx0ax0dx0aFlushing tablesx0dx0a正在執行FLUSH TABLES,等待其他線程關閉數據表。x0dx0aKilledx0dx0a發送了一個kill請求給某線程,那麼這個線程將會檢查kill標志位,同時會放棄下一個kill請求。MySQL會在每次的主循環中檢查kill標志位,不過有些情況下該線程可能會過一小段才能死掉。如果該線程程被其他線程鎖住了,那麼kill請求會在鎖釋放時馬上生效。x0dx0aLockedx0dx0a被其他查詢鎖住了。x0dx0aSending datax0dx0a正在處理SELECT查詢的記錄,同時正在把結果發送給客戶端。x0dx0ax0dx0aSorting for groupx0dx0a正在為GROUP BY做排序。x0dx0aSorting for orderx0dx0a正在為ORDER BY做排序。x0dx0aOpening tablesx0dx0a這個過程應該會很快,除非受到其他因素的干擾。例如,在執ALTER TABLE或LOCK TABLE語句行完以前,數據表無法被其他線程打開。正嘗試打開一個表。x0dx0aRemoving plicatesx0dx0a正在執行一個SELECT DISTINCT方式的查詢,但是MySQL無法在前一個階段優化掉那些重復的記錄。因此,MySQL需要再次去掉重復的記錄,然後再把結果發送給客戶端。x0dx0ax0dx0aReopen tablex0dx0a獲得了對一個表的鎖,但是必須在表結構修改之後才能獲得這個鎖。已經釋放鎖,關閉數據表,正嘗試重新打開數據表。x0dx0aRepair by sortingx0dx0a修復指令正在排序以創建索引。x0dx0aRepair with keycachex0dx0a修復指令正在利用索引緩存一個一個地創建新索引。它會比Repair by sorting慢些。x0dx0aSearching rows for updatex0dx0a正在講符合條件的記錄找出來以備更新。它必須在UPDATE要修改相關的記錄之前就完成了。x0dx0aSleepingx0dx0a正在等待客戶端發送新請求.x0dx0ax0dx0aSystem lockx0dx0a正在等待取得一個外部的系統鎖。如果當前沒有運行多個mysqld伺服器同時請求同一個表,那麼可以通過增加--skip-external-locking參數來禁止外部系統鎖。x0dx0aUpgrading lockx0dx0aINSERT DELAYED正在嘗試取得一個鎖表以插入新記錄。x0dx0aUpdatingx0dx0a正在搜索匹配的記錄,並且修改它們。x0dx0ax0dx0aUser Lockx0dx0a正在等待GET_LOCK()。x0dx0aWaiting for tablesx0dx0a該線程得到通知,數據表結構已經被修改了,需要重新打開數據表以取得新的結構。然後,為了能的重新打開數據表,必須等到所有其他線程關閉這個表。以下幾種情況下會產生這個通知:FLUSH TABLES tbl_name, ALTER TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLE,或OPTIMIZE TABLE。x0dx0awaiting for handler insertx0dx0aINSERT DELAYED已經處理完了所有待處理的插入操作,正在等待新的請求。x0dx0a大部分狀態對應很快的操作,只要有一個線程保持同一個狀態好幾秒鍾,那麼可能是有問題發生了,需要檢查一下。x0dx0a還有其他的狀態沒在上面中列出來,不過它們大部分只是在查看伺服器是否有存在錯誤是才用得著。x0dx0ax0dx0a例如如圖:x0dx0ax0dx0a3、explain來了解SQL執行的狀態x0dx0aexplain顯示了mysql如何使用索引來處理select語句以及連接表。可以幫助選擇更好的索引和寫出更優化的查詢語句。x0dx0a使用方法,在select語句前加上explain就可以了:x0dx0a例如:x0dx0aexplain select surname,first_name form a,b where a.id=b.idx0dx0a結果如圖x0dx0ax0dx0aEXPLAIN列的解釋x0dx0atablex0dx0a顯示這一行的數據是關於哪張表的x0dx0atypex0dx0a這是重要的列,顯示連接使用了何種類型。從最好到最差的連接類型為const、eq_reg、ref、range、indexhe和ALLx0dx0apossible_keysx0dx0a顯示可能應用在這張表中的索引。如果為空,沒有可能的索引。可以為相關的域從WHERE語句中選擇一個合適的語句x0dx0akeyx0dx0a實際使用的索引。如果為NULL,則沒有使用索引。很少的情況下,MYSQL會選擇優化不足的索引。這種情況下,可以在SELECT語句 中使用USE INDEX(indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制MYSQL忽略索引x0dx0akey_lenx0dx0a使用的索引的長度。在不損失精確性的情況下,長度越短越好x0dx0arefx0dx0a顯示索引的哪一列被使用了,如果可能的話,是一個常數x0dx0arowsx0dx0aMYSQL認為必須檢查的用來返回請求數據的行數x0dx0aExtrax0dx0a關於MYSQL如何解析查詢的額外信息。將在表4.3中討論,但這里可以看到的壞的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,結果是檢索會很慢x0dx0ax0dx0aextra列返回的描述的意義x0dx0aDistinctx0dx0a一旦MYSQL找到了與行相聯合匹配的行,就不再搜索了x0dx0aNot existsx0dx0aMYSQL優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標準的行,就不再搜索了x0dx0aRange checked for each Record(index map:#)x0dx0a沒有找到理想的索引,因此對於從前面表中來的每一個行組合,MYSQL檢查使用哪個索引,並用它來從表中返回行。這是使用索引的最慢的連接之一x0dx0aUsing filesortx0dx0a看到這個的時候,查詢就需要優化了。MYSQL需要進行額外的步驟來發現如何對返回的行排序。它根據連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行x0dx0aUsing indexx0dx0a列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對表的全部的請求列都是同一個索引的部分的時候x0dx0aUsing temporaryx0dx0a看到這個的時候,查詢需要優化了。這里,MYSQL需要創建一個臨時表來存儲結果,這通常發生在對不同的列集進行ORDER BY上,而不是GROUP BY上x0dx0aWhere usedx0dx0a使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。如果不想返回表中的全部行,並且連接類型ALL或index,這就會發生,或者是查詢有問題不同連接類型的解釋(按照效率高低的順序排序)x0dx0aconstx0dx0a表中的一個記錄的最大值能夠匹配這個查詢(索引可以是主鍵或惟一索引)。因為只有一行,這個值實際就是常數,因為MYSQL先讀這個值然後把它當做常數來對待x0dx0aeq_refx0dx0a在連接中,MYSQL在查詢時,從前面的表中,對每一個記錄的聯合都從表中讀取一個記錄,它在查詢使用了索引為主鍵或惟一鍵的全部時使用x0dx0arefx0dx0a這個連接類型只有在查詢使用了不是惟一或主鍵的鍵或者是這些類型的部分(比如,利用最左邊前綴)時發生。對於之前的表的每一個行聯合,全部記錄都將從表中讀出。這個類型嚴重依賴於根據索引匹配的記錄多少—越少越好x0dx0arangex0dx0a這個連接類型使用索引返回一個范圍中的行,比如使用>或<查找東西時發生的情況x0dx0aindexx0dx0a這個連接類型對前面的表中的每一個記錄聯合進行完全掃描(比ALL更好,因為索引一般小於表數據)x0dx0aALLx0dx0a這個連接類型對於前面的每一個記錄聯合進行完全掃描,這一般比較糟糕,應該盡量避免

J. mysql sql優化之 優化GROUP BY 和 DISTINCT

創建表tb_point 表

准備空的tb_box表

函數

編寫存儲過程,給tb_box表添加100萬條數據

修改關聯數據

好於

優於

在執行以下語句時會報錯:

前面在 https://www.jianshu.com/p/95e50fd017ea 文章中有提到這個問題,是直接修改sql_mode將 ONLY_FULL_GROUP_BY直接幹掉。但是在《高性能mysql》中有一段話是這樣的:

那麼既然指出不要直接修改 sql_mode,那麼我們應該如何讓沖突的GRUOPBY語句正確執行呢?

文中有提到,可以使用max()和min()函數來實現;但是這種方式使用max和min函數較真的人可能會說這樣寫的分組查詢有問題,確實如此。但是如果更加在乎查詢效率,這樣做也無可厚非。

如果,實在無法接受使用上面那種方式的話,可以這樣使用子查詢的方式來進行查詢:

書上對於這種方式有描述如下:
這樣寫更滿足關系理論,但是成本有點高,因為子查詢需要填充臨時表,而子查詢中創建的臨時表是沒有任何索引的。
作者認為這樣寫對性能有影響。

但是從我測得結果來看,子查詢的耗時反而更少。性能反而更佳。這個子查詢耗時0.4秒。而使用max方式耗時0.8秒。幾乎一倍。我的mysql版本是 5.7.22-log

為了解其中的原因,我們查看它的執行計劃:
可見,因為子查詢而產生了一層 DERIVED 臨時表,但是這個臨時表的Extra欄位有顯示 Using index、key裡面顯示自建索引。說明用到了索引。這是查詢性能可觀的一個重要原因吧;

另外我分別使用 SHOW PROFILE命令查看各部分耗時,對比之下。沒看到有哪部分耗時差別特別大,使用JOIN、MAX 耗時比上子查詢耗時都差不多是1倍

有些時候對一沒有建立索引的欄位,進行GRUOP BY時。會產生Using filesort 文件內排序。因為GRUOP BY是在排序的基礎上進行分組的。

如下面sql:

如果業務上不對排序有要求。那麼就可以禁止GRUOP BY的排序:

這樣就把Using filesort給幹掉了! 執行時間 1.237

當然,多數情況是多排序有要求的。此時也可以在GRUOP BY後面使用DESC和ASC關鍵字,使分組的結果集按需要的方向排序。如下:

分組查詢的一個變種就是要求mysql對分組結果再進行一次超級聚合。可以使用GROUP BY WITH ROLLUP 來實現這種邏輯,但可能性能不佳。因為通過查詢計劃分析出它是使用 Using temporary; Using filesort 來實現的。

使用WITH ROLLUP,查詢時間2.531秒。不使用0.774 秒。

1、所以,很多時候。我們在應用程序中做超級聚合是最好的!

2、當然也可使用UNION ALL 來實現:

3、還可以通過FROM子句嵌套使用子查詢: