日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

淘宝内部分享:MySQL MariaDB性能优化

發(fā)布時(shí)間:2025/3/21 数据库 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 淘宝内部分享:MySQL MariaDB性能优化 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


淘寶內(nèi)部分享:MySQL & MariaDB性能優(yōu)化

摘要:MySQL是目前使用最多的開源數(shù)據(jù)庫,但是MySQL數(shù)據(jù)庫的默認(rèn)設(shè)置性能非常的差,必須進(jìn)行不斷的優(yōu)化,而優(yōu)化是一個(gè)復(fù)雜的任務(wù),本文描述淘寶數(shù)據(jù)庫團(tuán)隊(duì)針對MySQL相關(guān)的數(shù)據(jù)庫優(yōu)化方案。

編者按:MySQL是目前使用最多的開源數(shù)據(jù)庫,但是MySQL數(shù)據(jù)庫的默認(rèn)設(shè)置性能非常的差,必須進(jìn)行不斷的優(yōu)化,而優(yōu)化是一個(gè)復(fù)雜的任務(wù),本文描述淘寶數(shù)據(jù)庫團(tuán)隊(duì)針對MySQL數(shù)據(jù)庫Metadata Lock子系統(tǒng)的優(yōu)化,hash_scan 算法的實(shí)現(xiàn)解析的性能優(yōu)化,TokuDB·版本優(yōu)化,以及MariaDB·的性能優(yōu)化。本文來自淘寶團(tuán)隊(duì)內(nèi)部經(jīng)驗(yàn)分享。

往期文章:淘寶內(nèi)部分享:怎么跳出MySQL的10個(gè)大坑


MySQL· 5.7優(yōu)化·Metadata Lock子系統(tǒng)的優(yōu)化

背景

引入MDL鎖的目的,最初是為了解決著名的bug#989,在MySQL 5.1及之前的版本,事務(wù)執(zhí)行過程中并不維護(hù)涉及到的所有表的Metatdata 鎖,極易出現(xiàn)復(fù)制中斷,例如如下執(zhí)行序列:

Session 1: BEGIN;
Session 1: INSERT INTO t1 VALUES (1);
Session 2: Drop table t1; --------SQL寫入BINLOG
Session 1: COMMIT; -----事務(wù)寫入BINLOG

在備庫重放 binlog時(shí),會先執(zhí)行DROP TABLE,再INSERT數(shù)據(jù),從而導(dǎo)致復(fù)制中斷。

在MySQL 5.5版本里,引入了MDL, 在事務(wù)過程中涉及到的所有表的MDL鎖,直到事務(wù)結(jié)束才釋放。這意味著上述序列的DROP TABLE 操作將被Session 1阻塞住直到其提交。

不過用過5.5的人都知道,MDL實(shí)在是個(gè)讓人討厭的東西,相信不少人肯定遇到過在使用mysqldump做邏輯備份時(shí),由于需要執(zhí)行FLUSH TABLES WITH READ LOCK (以下用FTWRL縮寫代替)來獲取全局GLOBAL的MDL鎖,因此經(jīng)常可以看到“wait for global read lock”之類的信息。如果備庫存在大查詢,或者復(fù)制線程正在執(zhí)行比較漫長的DDL,并且FTWRL被block住,那么隨后的QUERY都會被block住,導(dǎo)致業(yè)務(wù)不可用引發(fā)故障。

為了解決這個(gè)問題,Facebook為MySQL增加新的接口替換掉FTWRL 只創(chuàng)建一個(gè)read view ,并返回與read view一致的binlog位點(diǎn);另外Percona Server也實(shí)現(xiàn)了一種類似的辦法來繞過FTWRL,具體點(diǎn)擊文檔連接以及percona的博客,不展開闡述。

MDL解決了bug#989,卻引入了一個(gè)新的熱點(diǎn),所有的MDL鎖對象被維護(hù)在一個(gè)hash對象中;對于熱點(diǎn),最正常的想法當(dāng)然是對其進(jìn)行分區(qū)來分散熱點(diǎn),不過這也是Facebook的大神Mark Callaghan在report了bug#66473后才加入的,當(dāng)時(shí)Mark觀察到MDL_map::mutex的鎖競爭非常高,進(jìn)而推動官方改變。因此在MySQL 5.6.8及之后的版本中,引入了新參數(shù)metadata_locks_hash_instances來控制對mdl hash的分區(qū)數(shù)(Rev:4350);

不過故事還沒結(jié)束,后面的測試又發(fā)現(xiàn)哈希函數(shù)有問題,somedb. someprefix1 … .somedb .someprefix8 的hash key值相同,都被hash到同一個(gè)桶下面了,相當(dāng)于hash分區(qū)沒生效。這屬于hash算法的問題,喜歡考古的同學(xué)可以閱讀下bug#66473后面Dmitry Lenev的分析。

Mark進(jìn)一步的測試發(fā)現(xiàn)Innodb的hash計(jì)算算法比my_hash_sort_bin要更高效, Oracle的開發(fā)人員重開了個(gè)bug#68487來跟蹤該問題,并在MySQL5.6.15對hash key計(jì)算函數(shù)進(jìn)行優(yōu)化,包括fix 上面說的hash計(jì)算問題(Rev:5459),使用MurmurHash3算法來計(jì)算mdl key的hash值。

MySQL 5.7 對MDL鎖的優(yōu)化

在MySQL 5.7里對MDL子系統(tǒng)做了更為徹底的優(yōu)化。主要從以下幾點(diǎn)出發(fā):

第一,盡管對MDL HASH進(jìn)行了分區(qū),但由于是以表名+庫名的方式作為key值進(jìn)行分區(qū),如果查詢或者DML都集中在同一張表上,就會hash到相同的分區(qū),引起明顯的MDL HASH上的鎖競爭。

針對這一點(diǎn),引入了LOCK-FREE的HASH來存儲MDL_lock,LF_HASH無鎖算法基于論文"Split-Ordered Lists: Lock-Free Extensible Hash Tables",實(shí)現(xiàn)還比較復(fù)雜。 注:實(shí)際上LF_HASH很早就被應(yīng)用于Performance Schema,算是比較成熟的代碼模塊。由于引入了LF_HASH,MDL HASH分區(qū)特性自然直接被廢除了 。對應(yīng)WL#7305, PATCH(Rev:7249)

第二,從廣泛使用的實(shí)際場景來看,DML/SELECT相比DDL等高級別MDL鎖類型,是更為普遍的,因此可以針對性的降低DML和SELECT操作的MDL開銷。

為了實(shí)現(xiàn)對DML/SELECT的快速加鎖,使用了類似LOCK-WORD的加鎖方式,稱之為FAST-PATH,如果FAST-PATH加鎖失敗,則走SLOW-PATH來進(jìn)行加鎖。

每個(gè)MDL鎖對象(MDL_lock)都維持了一個(gè)long long類型的狀態(tài)值來標(biāo)示當(dāng)前的加鎖狀態(tài),變量名為MDL_lock::m_fast_path_state 舉個(gè)簡單的例子:(初始在sbtest1表上對應(yīng)MDL_lock::m_fast_path_state值為0)

Session 1: BEGIN;
Session 1: SELECT * FROM sbtest1 WHERE id =1; //m_fast_path_state = 1048576, MDL ticket 不加MDL_lock::m_granted隊(duì)列
Session 2: BEGIN;
Session 2: SELECT * FROM sbtest1 WHERE id =2; //m_fast_path_state=1048576+1048576=2097152,同上,走FAST PATH
Session 3: ALTER TABLE sbtest1 ENGINE = INNODB; //DDL請求加的MDL_SHARED_UPGRADABLE類型鎖被視為unobtrusive lock,可以認(rèn)為這個(gè)是比上述SQL的MDL鎖級別更高的鎖,并且不相容,因此被強(qiáng)制走slow path。而slow path是需要加MDL_lock::m_rwlock的寫鎖。m_fast_path_state = m_fast_path_state | MDL_lock::HAS_SLOW_PATH | MDL_lock::HAS_OBTRUSIVE
注:DDL還會獲得庫級別的意向排他MDL鎖或者表級別的共享可升級鎖,但為了表述方便,這里直接忽略了,只考慮涉及的同一個(gè)MDL_lock鎖對象。
Session 4: SELECT * FROM sbtest1 WHERE id =3; // 檢查m_fast_path_state &HAS_OBTRUSIVE,如果DDL還沒跑完,就會走slow path。

從上面的描述可以看出,MDL子系統(tǒng)顯式的對鎖類型進(jìn)行了區(qū)分(OBTRUSIVE or UNOBTRUSIVE),存儲在數(shù)組矩陣m_unobtrusive_lock_increment。 因此對于相容類型的MDL鎖類型,例如DML/SELECT,加鎖操作幾乎沒有任何讀寫鎖或MUTEX開銷。對應(yīng)WL#7304,?WL#7306?, PATCH(Rev:7067,Rev:7129)(Rev:7586)

第三,由于引入了MDL鎖,實(shí)際上早期版本用于控制Server和引擎層表級并發(fā)的THR_LOCK 對于Innodb而言已經(jīng)有些冗余了,因此Innodb表完全可以忽略這部分的開銷。

不過在已有的邏輯中,Innodb依然依賴THR_LOCK來實(shí)現(xiàn)LOCK TABLE tbname READ,因此增加了新的MDL鎖類型來代替這種實(shí)現(xiàn)。實(shí)際上代碼的大部分修改都是為了處理新的MDL類型,Innodb的改動只有幾行代碼。對應(yīng)WL#6671,PATCH(Rev:8232)

第四,Server層的用戶鎖(通過GET_LOCK函數(shù)獲取)使用MDL來重新實(shí)現(xiàn)。

用戶可以通過GET_LOCK()來同時(shí)獲取多個(gè)用戶鎖,同時(shí)由于使用MDL來實(shí)現(xiàn),可以借助MDL子系統(tǒng)實(shí)現(xiàn)死鎖的檢測。注意由于該變化,導(dǎo)致用戶鎖的命名必須小于64字節(jié),這是受MDL子系統(tǒng)的限制導(dǎo)致。對應(yīng)WL#1159, PATCH(Rev:8356)


MySQL·性能優(yōu)化·hash_scan 算法的實(shí)現(xiàn)解析

問題描述

首先,我們執(zhí)行下面的TestCase:

[js] view plaincopyprint?
  • --source?include/master-slave.inc??
  • --source?include/have_binlog_format_row.inc??
  • connection?slave;??
  • set?global?slave_rows_search_algorithms='TABLE_SCAN';??
  • connection?master;??
  • create?table?t1(id?int,?name?varchar(20);??
  • insert?into?t1?values(1,'a');??
  • insert?into?t2?values(2,?'b');??
  • ......??
  • insert?into?t3?values(1000,?'xxx');??
  • delete?from?t1;??
  • ---source?include/rpl_end.inc??
  • --source include/master-slave.inc--source include/have_binlog_format_row.incconnection slave;set global slave_rows_search_algorithms='TABLE_SCAN';connection master;create table t1(id int, name varchar(20);insert into t1 values(1,'a');insert into t2 values(2, 'b');......insert into t3 values(1000, 'xxx');delete from t1;---source include/rpl_end.inc隨著 t1 數(shù)據(jù)量的增大,rpl_hash_scan.test 的執(zhí)行時(shí)間會隨著 t1 數(shù)據(jù)量的增大而快速的增長,因?yàn)樵趫?zhí)行 'delete from t1;' 對于t1的每一行刪除操作,備庫都要掃描t1,即全表掃描,如果 select count(*) from t1 = N, 則需要掃描N次 t1 表, 則讀取記錄數(shù)為: O(N + (N-1) + (N-2) + .... + 1) = O(N^2),在 replication 沒有引入 hash_scan,binlog_format=row時(shí),對于無索引表,是通過 table_scan 實(shí)現(xiàn)的,如果一個(gè)update_rows_log_event/delete_rows_log_event 包含多行修改時(shí),每個(gè)修改都要進(jìn)行全表掃描來實(shí)現(xiàn),其 stack 如下:

    [js] view plaincopyprint?
  • #0?Rows_log_event::do_table_scan_and_update??
  • #1?0x0000000000a3d7f7?in?Rows_log_event::do_apply_event???
  • #2?0x0000000000a28e3a?in?Log_event::apply_event??
  • #3?0x0000000000a8365f?in?apply_event_and_update_pos??
  • #4?0x0000000000a84764?in?exec_relay_log_event???
  • #5?0x0000000000a89e97?in?handle_slave_sql?(arg=0x1b3e030)???
  • #6?0x0000000000e341c3?in?pfs_spawn_thread?(arg=0x2b7f48004b20)???
  • #7?0x0000003a00a07851?in?start_thread?()?from?/lib64/libpthread.so.0??
  • #8?0x0000003a006e767d?in?clone?()?from?/lib64/libc.so.6??
  • #0 Rows_log_event::do_table_scan_and_update #1 0x0000000000a3d7f7 in Rows_log_event::do_apply_event #2 0x0000000000a28e3a in Log_event::apply_event #3 0x0000000000a8365f in apply_event_and_update_pos #4 0x0000000000a84764 in exec_relay_log_event #5 0x0000000000a89e97 in handle_slave_sql (arg=0x1b3e030) #6 0x0000000000e341c3 in pfs_spawn_thread (arg=0x2b7f48004b20) #7 0x0000003a00a07851 in start_thread () from /lib64/libpthread.so.0 #8 0x0000003a006e767d in clone () from /lib64/libc.so.6這種情況下,往往會造成備庫延遲,這也是無索引表所帶來的復(fù)制延遲問題。

    如何解決問題:

  • RDS 為了解這個(gè)問題,會在每個(gè)表創(chuàng)建的時(shí)候檢查一下表是否包含主建或者唯一建,如果沒有包含,則創(chuàng)建一個(gè)隱式主建,此主建對用戶透明,用戶無感,相應(yīng)的show create, select * 等操作會屏蔽隱式主建,從而可以減少無索引表帶來的影響;
  • 官方為了解決這個(gè)問題,在5.6.6 及以后版本引入?yún)?shù) slave_rows_search_algorithms ,用于指示備庫在 apply_binlog_event時(shí)使用的算法,有三種算法TABLE_SCAN,INDEX_SCAN,HASH_SCAN,其中table_scan與index_scan是已經(jīng)存在的,本文主要研究HASH_SCAN的實(shí)現(xiàn)方式,關(guān)于參數(shù)slave_rows_search_algorithms的設(shè)置。
  • hash_scan 的實(shí)現(xiàn)方法:

    簡單的講,在 apply rows_log_event時(shí),會將 log_event 中對行的更新緩存在兩個(gè)結(jié)構(gòu)中,分別是:m_hash, m_distinct_key_list。 m_hash:主要用來緩存更新的行記錄的起始位置,是一個(gè)hash表; m_distinct_key_list:如果有索引,則將索引的值push 到m_distinct_key_list,如果表沒有索引,則不使用這個(gè)List結(jié)構(gòu); 其中預(yù)掃描整個(gè)調(diào)用過程如下: Log_event::apply_event

    [js] view plaincopyprint?
  • Rows_log_event::do_apply_event??
  • ???Rows_log_event::do_hash_scan_and_update???
  • ?????Rows_log_event::do_hash_row??(add?entry?info?of?changed?records)??
  • ???????if?(m_key_index?<?MAX_KEY)?(index?used?instead?of?table?scan)??
  • ?????????Rows_log_event::add_key_to_distinct_keyset?()??
  • Rows_log_event::do_apply_eventRows_log_event::do_hash_scan_and_update Rows_log_event::do_hash_row (add entry info of changed records)if (m_key_index < MAX_KEY) (index used instead of table scan)Rows_log_event::add_key_to_distinct_keyset ()當(dāng)一個(gè)event 中包含多個(gè)行的更改時(shí),會首先掃描所有的更改,將結(jié)果緩存到m_hash中,如果該表有索引,則將索引的值緩存至m_distinct_key_list List 中,如果沒有,則不使用這個(gè)緩存結(jié)構(gòu),而直接進(jìn)行全表掃描;

    執(zhí)行 stack 如下:

    [js] view plaincopyprint?
  • #0?handler::ha_delete_row???
  • #1?0x0000000000a4192b?in?Delete_rows_log_event::do_exec_row???
  • #2?0x0000000000a3a9c8?in?Rows_log_event::do_apply_row??
  • #3?0x0000000000a3c1f4?in?Rows_log_event::do_scan_and_update???
  • #4?0x0000000000a3c5ef?in?Rows_log_event::do_hash_scan_and_update???
  • #5?0x0000000000a3d7f7?in?Rows_log_event::do_apply_event???
  • #6?0x0000000000a28e3a?in?Log_event::apply_event??
  • #7?0x0000000000a8365f?in?apply_event_and_update_pos??
  • #8?0x0000000000a84764?in?exec_relay_log_event???
  • #9?0x0000000000a89e97?in?handle_slave_sql??
  • #10?0x0000000000e341c3?in?pfs_spawn_thread??
  • #11?0x0000003a00a07851?in?start_thread?()???
  • #12?0x0000003a006e767d?in?clone?()???
  • #0 handler::ha_delete_row #1 0x0000000000a4192b in Delete_rows_log_event::do_exec_row #2 0x0000000000a3a9c8 in Rows_log_event::do_apply_row #3 0x0000000000a3c1f4 in Rows_log_event::do_scan_and_update #4 0x0000000000a3c5ef in Rows_log_event::do_hash_scan_and_update #5 0x0000000000a3d7f7 in Rows_log_event::do_apply_event #6 0x0000000000a28e3a in Log_event::apply_event #7 0x0000000000a8365f in apply_event_and_update_pos #8 0x0000000000a84764 in exec_relay_log_event #9 0x0000000000a89e97 in handle_slave_sql #10 0x0000000000e341c3 in pfs_spawn_thread #11 0x0000003a00a07851 in start_thread () #12 0x0000003a006e767d in clone ()

    執(zhí)行過程說明:

    Rows_log_event::do_scan_and_update

    [js] view plaincopyprint?
  • open_record_scan()??
  • ??do??
  • ????next_record_scan()??
  • ??????if?(m_key_index?>?MAX_KEY)??
  • ?????????ha_rnd_next();??
  • ??????else??
  • ?????????ha_index_read_map(m_key?from?m_distinct_key_list)?????????
  • ??????entry=?m_hash->get()??
  • ??????m_hash->del(entry);??
  • ??????do_apply_row()??
  • ???while?(m_hash->size?>?0);??
  • open_record_scan()donext_record_scan()if (m_key_index > MAX_KEY)ha_rnd_next();elseha_index_read_map(m_key from m_distinct_key_list) entry= m_hash->get()m_hash->del(entry);do_apply_row()while (m_hash->size > 0);從執(zhí)行過程上可以看出,當(dāng)使用hash_scan時(shí),只會全表掃描一次,雖然會多次遍歷m_hash這個(gè)hash表,但是這個(gè)掃描是O(1),所以,代價(jià)很小,因此可以降低掃描次數(shù),提高執(zhí)行效率。

    hash_scan 的一個(gè) bug

    bug詳情:http://bugs.mysql.com/bug.php?id=72788
    bug原因:m_distinct_key_list 中的index key 不是唯一的,所以存在著對已經(jīng)刪除了的記錄重復(fù)刪除的問題。
    bug修復(fù):http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8494

    問題擴(kuò)展:

    • 在沒有索引的情況下,是不是把 hash_scan 打開就能提高效率,降低延遲呢?不一定,如果每次更新操作只一條記錄,此時(shí)仍然需要全表掃描,并且由于entry 的開銷,應(yīng)該會有后退的情況;
    • 一個(gè)event中能包含多少條記錄的更新呢?這個(gè)和表結(jié)構(gòu)以及記錄的數(shù)據(jù)大小有關(guān),一個(gè)event 的大小不會超過9000 bytes, 沒有參數(shù)可以控制這個(gè)size;
    • hash_scan 有沒有限制呢?hash_scan 只會對更新、刪除操作有效,對于binlog_format=statement 產(chǎn)生的 Query_log_event 或者binlog_format=row 時(shí)產(chǎn)生的 Write_rows_log_event 不起作用;


    TokuDB·版本優(yōu)化·7.5.0

    TokuDB 7.5.0大版本已發(fā)布,是一個(gè)里程碑的版本,這里談幾點(diǎn)優(yōu)化,以饗存儲引擎愛好者們。

    a) shutdown加速

    有用戶反饋TokuDB在shutdown的時(shí)候,半個(gè)小時(shí)還沒完事,非常不可接受。在shutdown的時(shí)候,TokuDB在干什么呢?在做checkpoint,把內(nèi)存中的節(jié)點(diǎn)數(shù)據(jù)序列化并壓縮到磁盤。

    那為什么如此耗時(shí)呢?如果tokudb_cache_size開的比較大,內(nèi)存中的節(jié)點(diǎn)會非常多,在shutdown的時(shí)候,大家都排隊(duì)等著被壓縮到磁盤(串行的)。

    在7.5.0版本,TokuDB官方針對此問題進(jìn)行了優(yōu)化,使多個(gè)節(jié)點(diǎn)并行壓縮來縮短時(shí)間。

    BTW: TokuDB在早期設(shè)計(jì)的時(shí)候已保留并行接口,只是一直未開啟。

    b) 內(nèi)節(jié)點(diǎn)讀取加速

    在內(nèi)存中,TokuDB內(nèi)節(jié)點(diǎn)(internal node)的每個(gè)message buffer都有2個(gè)重要數(shù)據(jù)結(jié)構(gòu):

    1) FIFO結(jié)構(gòu),保存{key, value}
    ?2) OMT結(jié)構(gòu),保存{key, FIFO-offset}

    由于FIFO不具備快速查找特性,就利用OMT來做快速查找(根據(jù)key查到value)。這樣,當(dāng)內(nèi)節(jié)點(diǎn)發(fā)生cache miss的時(shí)候,索引層需要做:

    1) 從磁盤讀取節(jié)點(diǎn)內(nèi)容到內(nèi)存
    ?2) 構(gòu)造FIFO結(jié)構(gòu)
    ?3) 根據(jù)FIFO構(gòu)造OMT結(jié)構(gòu)(做排序)

    由于TokuDB內(nèi)部有不少性能探(ji)針(shu),他們發(fā)現(xiàn)步驟3)是個(gè)不小的性能消耗點(diǎn),因?yàn)槊看味家裮essage buffer做下排序構(gòu)造出OMT,于是在7.5.0版本,把OMT的FIFO-offset(已排序)也持久化到磁盤,這樣排序的損耗就沒了。

    c) 順序?qū)懠铀?/strong>

    當(dāng)寫發(fā)生的時(shí)候,會根據(jù)當(dāng)前的key在pivots里查找(二分)當(dāng)前寫要落入哪個(gè)mesage buffer,如果寫是順序(或局部順序,數(shù)據(jù)走向?yàn)樽钣疫吢窂?的,就可以避免由"查找"帶來的額外開銷。



    如何判斷是順序?qū)懩?#xff1f;TokuDB使用了一種簡單的啟發(fā)式方法(heurstic):seqinsert_score積分式。如果:

    1) 當(dāng)前寫入落入最右節(jié)點(diǎn),對seqinsert_score加一分(原子)
    2) 當(dāng)前寫入落入非最右節(jié)點(diǎn),對seqinsert_score清零(原子) 當(dāng)seqinsert_score大于100的時(shí)候,就可以認(rèn)為是順序?qū)?#xff0c;當(dāng)下次寫操作發(fā)生時(shí),首先與最右的節(jié)點(diǎn)pivot進(jìn)行對比判斷,如果確實(shí)為順序?qū)?#xff0c;則會被寫到該節(jié)點(diǎn),省去不少compare開銷。方法簡單而有效。


    MariaDB· 性能優(yōu)化·filesort with small LIMIT optimization

    從MySQL 5.6.2/MariaDB 10.0.0版本開始,MySQL/MariaDB針對"ORDER BY ...LIMIT n"語句實(shí)現(xiàn)了一種新的優(yōu)化策略。當(dāng)n足夠小的時(shí)候,優(yōu)化器會采用一個(gè)容積為n的優(yōu)先隊(duì)列來進(jìn)行排序,而不是排序所有數(shù)據(jù)然后取出前n條。 這個(gè)新算法可以這么描述:(假設(shè)是ASC排序)

  • 建立一個(gè)只有n個(gè)元素的優(yōu)先隊(duì)列(堆),根節(jié)點(diǎn)為堆中最大元素
  • 根據(jù)其他條件,依次從表中取出一行數(shù)據(jù)
  • 如果當(dāng)前行的排序關(guān)鍵字小于堆頭,則把當(dāng)前元素替換堆頭,重新Shift保持堆的特性
  • 再取一條數(shù)據(jù)重復(fù)2步驟,如果沒有下一條數(shù)據(jù)則執(zhí)行5
  • 依次取出堆中的元素(從大到小排序),逆序輸出(從小到大排序),即可得ASC的排序結(jié)果
  • 這樣的算法,時(shí)間復(fù)雜度為m*log(n),m為索引過濾后的行數(shù),n為LIMIT的行數(shù)。而原始的全排序算法,時(shí)間復(fù)雜度為m*log(m)。只要n遠(yuǎn)小于m,這個(gè)算法就會很有效。

    不過在MySQL 5.6中,除了optimizer_trace,沒有好的方法來看到這個(gè)新的執(zhí)行計(jì)劃到底起了多少作用。MariaDB 10.013開始,提供一個(gè)系統(tǒng)狀態(tài),可以查看新執(zhí)行計(jì)劃調(diào)用的次數(shù):

    Sort_priority_queue_sorts
    ?描述: 通過優(yōu)先隊(duì)列實(shí)現(xiàn)排序的次數(shù)。(總排序次數(shù)=Sort_range+Sort_scan)
    ?范圍: Global, Session
    ?數(shù)據(jù)類型: numeric
    ?引入版本: MariaDB 10.0.13 此外,MariaDB還將此信息打入了Slow Log中。只要指定 log_slow_verbosity=query_plan,就可以在Slow Log中看到這樣的記錄:

    [js] view plaincopyprint?
  • #?Time:?140714?18:30:39??
  • ?#?User@Host:?root[root]?@?localhost?[]??
  • ?#?Thread_id:?3??Schema:?test??QC_hit:?No??
  • ?#?Query_time:?0.053857??Lock_time:?0.000188??Rows_sent:?11??Rows_examined:?100011??
  • ?#?Full_scan:?Yes??Full_join:?No??Tmp_table:?No??Tmp_table_on_disk:?No??
  • ?#?Filesort:?Yes??Filesort_on_disk:?No??Merge_passes:?0??Priority_queue:?Yes??
  • ?SET?timestamp=1405348239;SET?timestamp=1405348239;??
  • ?select?*?from?t1?where?col1?between?10?and?20?order?by?col2?limit?100;??
  • # Time: 140714 18:30:39# User@Host: root[root] @ localhost []# Thread_id: 3 Schema: test QC_hit: No# Query_time: 0.053857 Lock_time: 0.000188 Rows_sent: 11 Rows_examined: 100011# Full_scan: Yes Full_join: No Tmp_table: No Tmp_table_on_disk: No# Filesort: Yes Filesort_on_disk: No Merge_passes: 0 Priority_queue: YesSET timestamp=1405348239;SET timestamp=1405348239;select * from t1 where col1 between 10 and 20 order by col2 limit 100;"Priority_queue: Yes" 就表示這個(gè)Query利用了優(yōu)先隊(duì)列的執(zhí)行計(jì)劃(pt-query-digest 目前已經(jīng)可以解析 Priority_queue 這個(gè)列)。更多精彩內(nèi)容,敬請期待!
    本文轉(zhuǎn)載自MySQL.taobao.org ,感謝淘寶數(shù)據(jù)庫項(xiàng)目組丁奇、鳴嵩、彭立勛、皓庭、項(xiàng)仲、劍川、武藏、祁奚、褚霸、一工。審校:劉亞瓊

    總結(jié)

    以上是生活随笔為你收集整理的淘宝内部分享:MySQL MariaDB性能优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 黄色精品一区二区 | 国产视频在线看 | 亚洲永久精品在线观看 | 亚洲春色在线观看 | 九九影院最新理论片 | 公侵犯人妻一区二区三区 | 在线观看免费高清 | 永久免费看片在线观看 | 毛片网站免费观看 | 亚洲男女在线观看 | www色婷婷 | 免费av视屏 | 日韩精品一区二区亚洲av观看 | 三级在线观看网站 | 久久国内| 99色网| 中文字幕亚洲在线观看 | 欧美片一区二区 | 蜜臀av免费在线观看 | 免费视频www在线观看网站 | 一级欧美一级日韩片 | 草在线| 性一交一乱一色一免费无遮挡 | 日韩精选 | 全国男人天堂网 | 黄色性生活一级片 | 国产精品综合久久久久久 | 日韩精品――中文字幕 | 福利电影在线播放 | 国产v亚洲 | 丁香花电影高清在线阅读免费 | 欧美a级黄色片 | 亚洲av无码片一区二区三区 | 亚洲一区免费视频 | 欧美一级二级三级视频 | 中文字幕影片免费在线观看 | 欧美大胆a| 成人免费视频久久 | 亚洲涩视频 | 亚洲综合五月天婷婷丁香 | 色综合中文综合网 | 亚洲av成人无码久久精品老人 | 日本在线视频观看 | 麻豆蜜桃wwww精品无码 | 国产综合精品视频 | 最近中文字幕无免费 | 亚洲一区二区影院 | 免费av的网站 | 欧美午夜精品久久久久免费视 | 黄色av网站免费在线观看 | 亚洲视频在线观看网址 | 久草观看视频 | 亚洲狼人av | 99久99 | 91国内产香蕉 | 免费激情视频网站 | 少妇一级淫片日本 | 亚洲乱仑 | a级黄色录像 | 精品日本一区二区 | 香蕉啪啪网 | 干爹你真棒插曲mv在线观看 | 91在线一区二区三区 | 亚洲一区二区三区在线 | 婷婷狠狠操| 成人午夜免费毛片 | 国产剧情精品 | 好吊妞在线 | 伊人网址 | 亚洲精品图区 | 国产一区二区三区三州 | 粗大的内捧猛烈进出 | 电影《走路上学》免费 | 三上悠亚人妻中文字幕在线 | 夜夜操影视 | 高h调教冰块play男男双性文 | 久久一区二区电影 | 五月婷婷俺也去 | 日韩精品v | 五月激情六月丁香 | 午夜91 | 原创真实夫妻啪啪av | 黑人操中国女人视频 | 久久精品噜噜噜成人88aⅴ | 国产精品情侣呻吟对白视频 | 久草免费资源站 | 7799精品视频 | 日日夜夜狠狠操 | 日韩中文字幕网站 | 成人性生活免费视频 | 国产高清视频一区二区 | 欧美色一区二区三区在线观看 | 国产99视频在线 | 熟妇人妻系列aⅴ无码专区友真希 | 亚洲精美视频 | 精品区在线观看 | 女人高潮娇喘1分47秒 | 国产又粗又猛视频 | 日本高清视频网站 |