MySQL派生表合并優(yōu)化的原理和實(shí)現(xiàn)過(guò)程
引言
MySQL是一種流行的開(kāi)源關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),廣泛應(yīng)用于各種Web應(yīng)用程序和企業(yè)系統(tǒng)中。隨著數(shù)據(jù)量的增加和查詢復(fù)雜度的提高,優(yōu)化SQL查詢性能變得至關(guān)重要。派生表(Derived Table)是SQL查詢中常用的一種技術(shù),通過(guò)在主查詢中嵌套子查詢來(lái)實(shí)現(xiàn)更復(fù)雜的數(shù)據(jù)處理。然而,派生表的使用有時(shí)會(huì)導(dǎo)致系統(tǒng)的性能瓶頸。
為了解決這一問(wèn)題,MySQL引入了派生表合并優(yōu)化(Derived Table Merging Optimization)。本文將詳細(xì)介紹派生表合并優(yōu)化的原理及在MySQL中的實(shí)現(xiàn)。
何為派生表?
派生表是一個(gè)臨時(shí)表,它是由子查詢的結(jié)果集生成并在主查詢中使用。簡(jiǎn)單來(lái)講,就是將FROM子句中出現(xiàn)的檢索結(jié)果集當(dāng)成一張表,比如 FROM一個(gè)SELECT構(gòu)造的子查詢,這個(gè)子查詢就是一個(gè)派生表;SELECT一個(gè)視圖,這個(gè)視圖就是一個(gè)派生表;SELECT一個(gè)WITH構(gòu)造的臨時(shí)表(Common table expression,CTE),這個(gè)CTE表就是一個(gè)派生表。如下圖舉例所示:
圖1 子查詢語(yǔ)句樣例
MySQL優(yōu)化器處理派生表有兩種策略:
第一種,將派生表物化為一個(gè)臨時(shí)表;
第二種,將派生表合并到外查詢塊中。
派生表物化為一個(gè)臨時(shí)表,可能會(huì)引發(fā)性能問(wèn)題,如下情況:
大數(shù)據(jù)量子查詢:派生表的結(jié)果集可能非常大,導(dǎo)致內(nèi)存消耗和磁盤(pán)I/O增加。
復(fù)雜查詢:多層嵌套查詢或包含多個(gè)派生表的查詢,會(huì)使優(yōu)化器難以選擇最佳執(zhí)行計(jì)劃。
不可索引:派生表的結(jié)果集是臨時(shí)的,無(wú)法直接使用索引進(jìn)行優(yōu)化。
為了解決這些問(wèn)題,MySQL 引入了派生表合并優(yōu)化。
派生表合并優(yōu)化原理
派生表合并優(yōu)化的核心思想是將派生表的子查詢合并到主查詢中,從而避免生成臨時(shí)表。具體來(lái)說(shuō)就是,優(yōu)化器會(huì)嘗試將派生表的子查詢展開(kāi),并直接嵌入到主查詢的執(zhí)行計(jì)劃中。這樣可以減少臨時(shí)表的使用,降低內(nèi)存和磁盤(pán)I/O的負(fù)擔(dān),從而提高查詢性能。
下文將通過(guò)案例對(duì)派生表合并優(yōu)化進(jìn)行詳細(xì)說(shuō)明。
1.案例分析
創(chuàng)建如下兩張表:
CREATE TABLE `departments` ( `id` int NOT NULL, `name` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; CREATE TABLE `employees` ( `id` int NOT NULL, `name` varchar(50) DEFAULT NULL, `department_id` int DEFAULT NULL, `salary` decimal(10,2) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB;
對(duì)于下述的查詢語(yǔ)句:
SELECT t1.department_id, t2.name, t1.total_salary FROM (SELECT department_id, SUM(salary) total_salary FROM employees GROUP BY department_id) t1 JOIN (SELECT id, name FROM departments WHERE name='Human Resources') t2 ON t1.department_id = t2.id;
關(guān)閉optimizer_switch(優(yōu)化器開(kāi)關(guān))的derived_merge選項(xiàng),對(duì)應(yīng)的執(zhí)行計(jì)劃如下:
+----+-------------+-------------+------------+------+---------------+-------------+---------+------------------+------+----------+-----------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-------------+------------+------+---------------+-------------+---------+------------------+------+----------+-----------------+ | 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | Using where | | 1 | PRIMARY | <derived3> | NULL | ref | <auto_key0> | <auto_key0> | 4 | t1.department_id | 2 | 100.00 | NULL | | 3 | DERIVED | departments | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where | | 2 | DERIVED | employees | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using temporary | +----+-------------+-------------+------------+------+---------------+-------------+---------+------------------+------+----------+-----------------+ 4 rows in set, 1 warning (0.01 sec)
select_type列出現(xiàn)兩行DERIVED類型, 說(shuō)明派生表沒(méi)有合并,派生表會(huì)物化為臨時(shí)表。
執(zhí)行EXPLAIN ANALYZE進(jìn)一步分析,可知兩個(gè)子查詢都是物化為臨時(shí)表后,再執(zhí)行JOIN。
EXPLAIN: -> Nested loop inner join (actual time=0.304..0.308 rows=1 loops=1) -> Table scan on t2 (cost=2.73 rows=2) (actual time=0.003..0.003 rows=1 loops=1) -> Materialize (cost=0.55 rows=1) (actual time=0.163..0.164 rows=1 loops=1) -> Filter: (departments.`name`='Human Resources') (cost=0.55 rows=1) (actual time=0.103..0.125 rows=1 loops=1) -> Table scan on departments (cost=0.55 rows=3) (actual time=0.095..0.114 rows=3 loops=1) -> Index lookup on t1 using <auto_key0> (department_id=t2.id) (actual time=0.004..0.006 rows=1 loops=1) -> Materialize (actual time=0.137..0.139 rows=1 loops=1) -> Table scan on <temporary> (actual time=0.001..0.003 rows=3 loops=1) -> Aggregate using temporary table (actual time=0.102..0.104 rows=3 loops=1) -> Table scan on employees (cost=0.65 rows=4) (actual time=0.040..0.056 rows=4 loops=1) 1 row in set (0.00 sec)
開(kāi)啟optimizer_switch(優(yōu)化器開(kāi)關(guān))的derived_merge選項(xiàng),對(duì)應(yīng)的執(zhí)行計(jì)劃如下:
+----+-------------+-------------+------------+------+---------------+-------------+---------+---------------------+------+----------+-----------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------------+------------+------+---------------+-------------+---------+---------------------+------+----------+-----------------+ | 1 | PRIMARY | departments | NULL | ALL | PRIMARY | NULL | NULL | NULL | 1 | 100.00 | Using where | | 1 | PRIMARY | <derived2> | NULL | ref | <auto_key0> | <auto_key0> | 5 | test.departments.id | 2 | 100.00 | NULL | | 2 | DERIVED | employees | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using temporary | +----+-------------+-------------+------------+------+---------------+-------------+---------+---------------------+------+----------+-----------------+ 3 rows in set, 1 warning (0.00 sec)
從執(zhí)行計(jì)劃可以看出,select_type列上只有一行為DERIVED類型,說(shuō)明發(fā)生了派生表合并。
執(zhí)行EXPLAIN ANALYZE進(jìn)一步分析,employees表上的子查詢?nèi)匀粫?huì)被物化為臨時(shí)表。departments表上的子查詢(派生表)進(jìn)行了合并優(yōu)化,departments表直接與臨時(shí)表t1進(jìn)行JOIN。
EXPLAIN: -> Nested loop inner join (actual time=0.271..0.295 rows=1 loops=1) -> Filter: (departments.`name` = 'Human Resources') (cost=0.55 rows=1) (actual time=0.103..0.122 rows=1 loops=1) -> Table scan on departments (cost=0.55 rows=3) (actual time=0.095..0.112 rows=3 loops=1) -> Index lookup on t1 using <auto_key0> (department_id=departments.id) (actual time=0.005..0.007 rows=1 loops=1) -> Materialize (actual time=0.164..0.166 rows=1 loops=1) -> Table scan on <temporary> (actual time=0.002..0.004 rows=3 loops=1) -> Aggregate using temporary table (actual time=0.114..0.117 rows=3 loops=1) -> Table scan on employees (cost=0.65 rows=4) (actual time=0.044..0.065 rows=4 loops=1) 1 row in set (0.00 sec)
對(duì)比derived_merge選項(xiàng)開(kāi)啟和關(guān)閉的兩個(gè)執(zhí)行計(jì)劃可知,開(kāi)啟派生表合并優(yōu)化特性后,departments表上的子查詢(派生表)不再物化為臨時(shí)表,而是合并到了父查詢,進(jìn)而簡(jiǎn)化了執(zhí)行計(jì)劃,并提高了執(zhí)行效率。
另外,也可以發(fā)現(xiàn),并不是所有派生表都可以合并優(yōu)化,比如,案例中的employees表上的子查詢(派生表),因?yàn)楹芯酆虾瘮?shù),就無(wú)法進(jìn)行合并優(yōu)化。
2.應(yīng)用場(chǎng)景限制
如下場(chǎng)景中派生表合并優(yōu)化是無(wú)效的:
1)派生表中含有聚合函數(shù),或者含有DISTINCT、GROUP BY、HAVING這些分組子句。比如,案例中的派生表t1包含了聚合函數(shù)和GROUP BY分組就無(wú)法合并優(yōu)化。
2)派生表的SELECT列表中有子查詢,也就是標(biāo)量子查詢。比如:
select * from (select stuno, course_no, (select course_name from course c where c.course_no = a.course_no) as course_name, score from score a) b where b.stuno = 1;
因?yàn)榕缮韇的select 列表中有標(biāo)量子查詢,無(wú)法合并,會(huì)被物化。
3)分配了用戶變量。比如:
select (@i := @i + 1) as rownum, stuno, course_no, course_name, score from ((select a.stuno, a.course_no, b.course_name, a.score from score a left join course b on a.course_no = b.course_no) dt, (select (@i := 0) num) c) where stuno = 1;
上面這個(gè)例子使用用戶變量的形式給記錄加了行號(hào),不能合并。
4)如果合并會(huì)導(dǎo)致外查詢塊中超過(guò)61張基表的連接訪問(wèn),優(yōu)化器會(huì)選擇物化派生表。
5)UNION或UNION ALL。比如:
select id, c1from (select id, c1 from t1 union select id, c1 from t2) dt where dt.id = 1;
因?yàn)榕缮韉t有union操作,無(wú)法合并,會(huì)被物化。
6)對(duì)于視圖而言,創(chuàng)建視圖時(shí)如果指定了ALGORITHM=TEMPTABLE,它會(huì)阻止合并,這個(gè)屬性的優(yōu)先級(jí)比優(yōu)化器開(kāi)關(guān)的優(yōu)先級(jí)要高。
7)派生表中含LIMIT子句,因?yàn)楹喜?huì)導(dǎo)致結(jié)果集改變。比如:
select * from (select id,c1 from t1 limit 10) a where a. id=1;
8)只引用了字面量值。比如:
select * from (select '1' as c1, 2 as c2 ) a;
源碼分析
1.背景知識(shí)
我們使用的MySQL代碼版本號(hào)為8.0.22。在介紹派生表代碼實(shí)現(xiàn)之前,先了解下MySQL描述一條查詢的邏輯語(yǔ)法樹(shù)結(jié)構(gòu),有4個(gè)較為核心的類:
SELECT_LEX_UINT
對(duì)于一個(gè)query expression的描述結(jié)構(gòu),其中可以包含union/union all等多個(gè)query block的集合運(yùn)算,同時(shí)SELECT_LEX_UNIT也根據(jù)query的結(jié)構(gòu)形成遞歸包含關(guān)系。
SELECT_LEX
對(duì)于一個(gè)query block的描述結(jié)構(gòu),就是我們最為熟悉SPJ(選擇Selection、投影Projection、連接Join) + group by + order by + select list... 這樣的一個(gè)查詢塊,一個(gè)SELECT_LEX_UNIT中可能包含多個(gè)SELECT_LEX,而SELECT_LEX內(nèi)部則也可能嵌套包含其他SELECT_LEX_UNIT。
Item
對(duì)于expression的描述結(jié)構(gòu),例如on條件、where條件、投影列等,都是用這個(gè)類來(lái)描述一個(gè)個(gè)表達(dá)式的,Item系統(tǒng)是MySQL SQL層代碼中最為復(fù)雜的子系統(tǒng)之一,其構(gòu)成了表達(dá)式樹(shù)。
TABLE_LIST
對(duì)于表信息的描述結(jié)構(gòu)。TABLE_LIST不僅僅針對(duì)SQL表達(dá)式中的物理表,也可以表示其他類型的表,例如視圖、臨時(shí)表、派生表等。此外,TABLE_LIST類還用于處理別名和連接等信息。
TABLE_LIST類是MySQL查詢處理的核心部分,涵蓋了SQL表達(dá)式中的各種表類型。以案例中的SQL查詢語(yǔ)句為例,在派生表合并優(yōu)化前,其對(duì)應(yīng)的類實(shí)例映射關(guān)系如下:
圖2 派生表合并優(yōu)化前的SQL語(yǔ)句
圖3 派生表合并優(yōu)化前的邏輯語(yǔ)法樹(shù)
圖2為SQL表達(dá)式,圖3為MySQL處理后對(duì)應(yīng)的邏輯語(yǔ)法樹(shù)。圖2顏色涵蓋的SQL語(yǔ)句范圍與圖3相同顏色的類實(shí)例一一對(duì)應(yīng)。比如,圖2米黃色涵蓋了整條SELECT語(yǔ)句(query block),也就對(duì)應(yīng)著圖3的SELECT_LEX1實(shí)例;圖2最外層的淺灰色包含了米黃色區(qū)域,代表整條SQL語(yǔ)句(query expression),對(duì)應(yīng)著圖3的SELECT_LEX_UINT1實(shí)例(不涉及UNION操作,SELECT_LEX_UINT1只包含SELECT_LEX1,即一個(gè)SELECT_LEX實(shí)例)。
圖2中用括號(hào)圈起來(lái)的部分,就是一個(gè)SELECT_LEX_UNIT,而每個(gè)SELECT toke開(kāi)始的一個(gè)query block,就是一個(gè)SELECT_LEX,而在外層的SELECT_LEX中,會(huì)嵌套子查詢,用一個(gè)SELECT_LEX_UNIT描述,子查詢中可以是任意查詢形態(tài),再包含多個(gè)SELECT_LEX,從而形成SELECT_LEX_UNIT -> SELECT_LEX -> SELECT_LEX_UNIT -> SELECT_LEX ... 這種相互嵌套的結(jié)構(gòu)。
最外層的 query block(SELECT_LEX1)有兩個(gè)派生表(t1、t2)。t1 和 t2 通過(guò) derived 指針?lè)謩e指子查詢 query expression(SELECT_LEX_UINT3、SELECT_LEX_UINT2)。
2. 代碼實(shí)現(xiàn)
MySQL主要在prepare階段處理派生表的合并優(yōu)化,詳細(xì)的函數(shù)調(diào)用和處理過(guò)程如下:
-> Sql_cmd_dml::prepare -> Sql_cmd_select::prepare_inner -> SELECT_LEX::prepare 頂層 query block 的處理,全局入口 -> SELECT_LEX::resolve_placeholder_tables 處理query block中的第一個(gè) derived table -> TABLE_LIST::resolve_derived -> 創(chuàng)建Query_result_union對(duì)象,在執(zhí)行derived子查詢時(shí),用來(lái)向臨時(shí)表里寫(xiě)入結(jié)果數(shù)據(jù) -> 調(diào)用內(nèi)層嵌套SELECT_LEX_UNIT::prepare,對(duì)derived table對(duì)應(yīng)的子查詢做遞歸處理 -> SELECT_LEX::prepare -> 判斷derived中的子查詢是否允許merge到外層,當(dāng)滿足如下任一條件時(shí),“有可能”可以merge到外層: 1. derived table屬于最外層查詢 2. 屬于最外層的子查詢之中,且query是一個(gè)SELECT查詢 -> SELECT_LEX::resolve_placeholder_tables 嵌套處理derived table這個(gè)子查詢內(nèi)部的derived table... ... 處理query block中其他的各個(gè)組件,包括condition/group by/rollup/distinct/order by... -> SELECT_LEX::transform_scalar_subqueries_to_join_with_derived ... 一系列對(duì)query block(Item中的)處理,略過(guò) -> SELECT_LEX::apply_local_transforms 做最后的一些查詢變換(針對(duì)最外層query block) 1. 簡(jiǎn)化join,把嵌套的join表序列盡可能展開(kāi),去掉無(wú)用的join,outer join轉(zhuǎn)inner join等 2. 對(duì)分區(qū)表做靜態(tài)剪枝 -> SELECT_LEX::push_conditions_to_derived_tables(針對(duì)最外層query block) 外 query block 中與 derived table 相關(guān)的條件會(huì)推入到派生表中 -> 至此derived table對(duì)應(yīng)的子查詢部分resolve完成 -> TABLE_LIST::is_mergeable -> SELECT_LEX_UNIT::is_mergeable 判斷當(dāng)前 derived table 是否可以merge到外層,要同時(shí)滿足如下的要求:(只支持最簡(jiǎn)單的SPJ查詢) 1. derived table query expression 沒(méi)有union 2. derived table query block 沒(méi)有聚合/窗口函數(shù)+group by + 沒(méi)有having + 沒(méi)有distinct + 有table + 沒(méi)有window + 沒(méi)有l(wèi)imit -> SELECT_LEX::merge_derived,確定可以展開(kāi)到外層后,執(zhí)行 merge_derived 動(dòng)作 -> 再做一系列的檢查看是否可以merge 1. 外層query block是否允許merge,例如CREATE VIEW/SHOW CREATE這樣的命令,不允許做merge 2. 基于啟發(fā)式,檢查derived子查詢的投影列是否有子查詢,有則不做merge 3. 如果外層有straight_join,而derived子查詢中有semi-join/anti-join,則不允許merge 4. 外層表的數(shù)量達(dá)到MySQL能處理的最大值 -> 通過(guò)檢查后,開(kāi)始merge 1. 把內(nèi)層join列表合并到外層中 2. 把where條件與外層的where條件做AND組合 3. 把投影列合并到外層投影列中 -> 對(duì)于不能展開(kāi)的,采用物化方式執(zhí)行,setup_materialized_derived 處理query block中的其它 derived table,... -> resolve_placeholder_tables 處理完成 頂層 query block 的其它處理 ...
案例中的SQL語(yǔ)句經(jīng)過(guò)上面的派生表的合并優(yōu)化處理后,其對(duì)應(yīng)的映射關(guān)系如下:
圖4 派生表合并優(yōu)化后的SQL語(yǔ)句
圖5 派生表合并優(yōu)化后的邏輯語(yǔ)法樹(shù)
對(duì)比合并優(yōu)化前,有如下變化:(圖4的SQL語(yǔ)句已基于圖5的邏輯語(yǔ)法樹(shù)等價(jià)變換)
1)派生表t2所指向的內(nèi)部 query expression(SELECT_LEX_UINT2/SELECT_LEX2)已消除。
2)SELECT_LEX2中的物理表departments上移至外部query block(SELECT_LEX1)的JOIN運(yùn)算中。
3)SELECT_LEX2中的WHERE條件合并到SELECT_LEX1。
4)SELECT_LEX1中針對(duì)派生表t2的投影,替換為物理表departments。
原理證明
前文描述了MySQL派生表合并優(yōu)化的具體實(shí)現(xiàn),那么,如何從原理上證明該優(yōu)化方法的正確性呢?可以嘗試根據(jù)關(guān)系代數(shù)定理對(duì)其進(jìn)行論證。
先簡(jiǎn)化場(chǎng)景,假設(shè)有兩個(gè)表,一個(gè)是主查詢(主表)R,一個(gè)是派生表D。在沒(méi)有合并優(yōu)化之前,查詢可能是這樣的形式:
1)外層查詢從派生表中選擇數(shù)據(jù):σ條件1(D)
2)派生表D是從另一個(gè)或多個(gè)表導(dǎo)出的結(jié)果,通過(guò)一定的操作如選擇σ條件2、投影π屬性或連接?等得到。
不考慮具體實(shí)現(xiàn)的復(fù)雜性,讓我們通過(guò)一個(gè)簡(jiǎn)單查詢的例子來(lái)說(shuō)明外層查詢和派生表合并的效果。假設(shè)派生表D是從主表R通過(guò)選擇操作產(chǎn)生的:D = σ條件2(R),而外層查詢又對(duì)D進(jìn)行選擇:σ條件1(D)。
根據(jù)關(guān)系代數(shù)的選擇的疊加律(σa(σb(R)) = σa ∧ b(R)),可以合并這兩個(gè)選擇操作為一個(gè)操作,直接作用在主表R上:σ條件1 ∧ 條件2(R)。
這樣,外層查詢和派生表D就被合并成了一個(gè)直接對(duì)原始表R進(jìn)行操作的查詢,省去了創(chuàng)建和訪問(wèn)派生表D的開(kāi)銷。
對(duì)于更復(fù)雜的派生表,它們可能通過(guò)多個(gè)操作,如連接、投影和選擇,從一個(gè)或多個(gè)表導(dǎo)出。針對(duì)這樣的情況,基于關(guān)系代數(shù)的性質(zhì),比如選擇的疊加律和交換律、投影的結(jié)合律等,通過(guò)相應(yīng)的關(guān)系代數(shù)變換,所有這些操作的組合都可以被重寫(xiě)為直接作用于原始表上的一系列操作,也就證明了MySQL的這一優(yōu)化方式是有效的。
總結(jié)
本文從一個(gè)案例出發(fā)梳理了MySQL派生表合并優(yōu)化的流程實(shí)現(xiàn)和優(yōu)化原理,并對(duì)優(yōu)化前后同一條SQL語(yǔ)句在代碼層面的類實(shí)例映射關(guān)系進(jìn)行了對(duì)比。MySQL派生表合并的代碼實(shí)現(xiàn)細(xì)節(jié)比較多,篇幅有限,不再贅述,希望本文能夠作為一個(gè)參考,幫助感興趣的讀者進(jìn)一步研究這部分源碼。
到此這篇關(guān)于MySQL派生表合并優(yōu)化的原理和實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)MySQL派生表合并內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql group by having 實(shí)例代碼
mysql中g(shù)roup by語(yǔ)句用于分組查詢,可以根據(jù)給定數(shù)據(jù)列的每個(gè)成員對(duì)查詢結(jié)果進(jìn)行分組統(tǒng)計(jì),最終得到一個(gè)分組匯總表, 經(jīng)常和having一起使用,需要的朋友可以參考下2016-11-11SELinux導(dǎo)致PHP連接MySQL異常Can''t connect to MySQL server的解決方法
這篇文章主要介紹了SELinux導(dǎo)致PHP連接MySQL異常Can't connect to MySQL server的解決方法,有2種,一是設(shè)置允許,二是關(guān)閉SELinux,需要的朋友可以參考下2014-07-07MySQL5綠色版windows下安裝總結(jié)(推薦)
這篇文章主要介紹了MySQL5綠色版windows下安裝總結(jié),需要的朋友可以參考下2017-03-03MySQL優(yōu)化案例系列-mysql分頁(yè)優(yōu)化
這篇文章主要介紹了MySQL優(yōu)化案例系列-mysql分頁(yè)優(yōu)化,需要的朋友可以參考下2016-08-08MySQL數(shù)據(jù)庫(kù)的InnoDB和MyISAM存儲(chǔ)引擎的區(qū)別及說(shuō)明
InnoDB是MySQL的默認(rèn)存儲(chǔ)引擎,它支持事務(wù)、外鍵和行級(jí)鎖定,具有更好的并發(fā)控制性能和崩潰恢復(fù)能力,而MyISAM不支持事務(wù)和外鍵,使用表級(jí)鎖定,適合讀操作頻繁的場(chǎng)景2024-12-12探究MySQL中索引和提交頻率對(duì)InnoDB表寫(xiě)入速度的影響
這篇文章主要介紹了MySQL中索引和提交頻率對(duì)InnoDB表寫(xiě)入速度的影響,作者通過(guò)實(shí)際測(cè)試運(yùn)行時(shí)間的對(duì)比來(lái)驗(yàn)證,需要的朋友可以參考下2015-05-05在SpringBoot中實(shí)現(xiàn)WebSocket會(huì)話管理的方案
在構(gòu)建實(shí)時(shí)通信應(yīng)用時(shí),WebSocket 無(wú)疑是一個(gè)強(qiáng)大的工具,SpringBoot提供了對(duì)WebSocket的支持,本文旨在探討如何在 Spring Boot 應(yīng)用中實(shí)現(xiàn) WebSocket 會(huì)話管理,我們將通過(guò)一個(gè)模擬的場(chǎng)景一步步展開(kāi)討論,需要的朋友可以參考下2023-11-11