萬字長文之分庫分表里如何優化分頁查詢?【后端面試題 | 中間件 | 數據庫 | MySQL | 分庫分表 | 分頁查詢】

分庫分表的一般做法

一般會使用三種算法:

  1. 哈希分庫分表:根據分庫分表鍵算出一個哈希值,根據這個哈希值選擇一個數據庫。最常見的就是數字類型的字段作為分庫分表鍵,然后取余。比如在訂單表里,可以按照買家的ID除以8的余數進行分表
  2. 范圍分庫分表:將某個數據按照范圍大小進行分段。比如說根據ID,[0,1000)在一張表,[1000,2000)在另外一張表。最常見的應該是按照日期進行分庫分表,比如每個月一張表
  3. 中間表:引入一個中間表來記錄數據所在的目標表。一般是記錄主鍵到目標表的映射關系。
    在這里插入圖片描述
    這三者并不互斥,也就是說可以考慮使用哈希分庫分表,同時引入一個中間表;也可以先進行范圍分庫分表,再引入一個中間表。

分庫分表中間件的形態

  1. SDK形態:通過依賴的形式引入代碼里,比如Java的依賴ShardingSphere
  2. Proxy形態:獨立部署的分庫分表中間件,對于所有的業務方來說,就像一個普通的數據庫,業務方的查詢發送過去后,就會執行分庫分表,發起實際的查詢,再把查詢結果返回給業務方。ShardingSphere也支持這種形態。
    在這里插入圖片描述
  3. Sidecar形態:提供了一個分庫分表的Sidecar,但是現在并沒有非常成熟的產品

Sidecar是一種分庫分表中間件的形態。它是一個理論上的概念,指的是一個獨立的組件,為應用程序提供分庫分表的功能。在這種形態下,Sidecar作為應用程序的伴隨服務運行,類似于服務網格中的Sidecar容器,它與應用程序實例部署在一起,但作為獨立的進程運行。
在這里插入圖片描述

其中,SDK形態的性能最好,但是和語言強耦合。
Proxy形態性能最差,因為所有的數據庫查詢都發送給它了,很容易成功性能瓶頸。尤其單機部署Proxy的話,還面臨著單節點故障的問題。優點是跟編程語言無關,部署一個Proxy之后可以給使用不同編程語言的業務使用。同時,業務方可以輕易地從單庫單表切換到分庫分表。
在這里插入圖片描述
Sidecar 目前還沒有成熟的產品,但是從架構上來說它的性能應該介于 SDK 和 Proxy 之間,并且也沒有單體故障、集群管理等煩惱。

面試準備

還需要弄清楚幾個問題:

  • 公司是如何解決分庫分表中的分頁問題的?
  • 有沒有因為排序或分頁而引起的性能問題?最終怎么解決的

還可以去看看公司的監控數據,注意下分頁查詢的響應時間。并且在業務高峰期或是頻繁執行分頁的時候,看看內存和CPU的使用率。這些數據可以作為分頁查詢比較引起性能問題的證據

面試策略上來說,最好把分頁查詢優化作為你性能優化的一個舉措,可以進一步和前面的查詢優化、數據庫參數優化相結合,這樣方案會更完善,能力會更全面。

如果面試官問到了數據庫性能優化和數據庫分頁查詢,你都可以嘗試把話題引導到分頁查詢上。

基本思路

可以嘗試介紹一下是如何優化數據庫性能的,比如SQL本身優化、數據庫優化,然后羅列出準備的SQL案例,說明你在SQL優化方面做過哪些事情,比如優化過分庫分表的查詢,其中最典型的就是優化分頁查詢。
假設之前是全局查詢,現在采用禁用跨頁查詢的方案來優化

最開始我在公司監控慢查詢的時候,發現有一個分頁查詢非常慢。這個分頁查詢是按照更新時間降序來排序的。后來我發現那個分頁查詢用的是全局查詢法,因為這個接口原本是提供給 Web 端用的,而 Web 端要支持跨頁查詢,所以只能使用全局查詢法。當查詢的頁數靠后的時候,響應時間就非常長。 后來我們公司搞出 App 之后,類似的場景直接復用了這個接口。但是事實上在 App 上是沒有跨頁需求的。所以我就直接寫了一個新接口,這個接口要求分頁的時候帶上上一頁的最后一條數據的更新時間。也就是我用這個更新時間構造了一個查詢條件,只查詢早于這個時間的數據。那么分頁查詢的時候 OFFSET 就永遠被我控制在 0 了,查詢的時間就非常穩定了。

最后你可以加一個總結。

分頁查詢在分庫分表里面是一個很難處理的問題,要么查詢可能有性能問題,比如說這里使用的全局查詢法,要么就是要求業務折中,比如說我優化后禁用了跨頁,以及要求數據平均分布的平均分頁法,當然還有各方面都不錯,但是實現比較復雜的二次查詢法、中間表法。

當面試官追問你其中細節的時候,你就可以這樣來引導。

全局查詢

理論上說,分頁查詢要在全局有序的情況下進行,但是在分庫分表以后,要做到全局有序就很難了。假如說我們的數據庫order_tab是以buyer_id % 2來進行分表的,如果你要執行一個語句

SELECT * FROM order_tab ORDER BY id LIMIT 4 OFFSET 2

實際執行查詢的時候,就要考慮各種數據的分布情況。

  • 符合條件的數據全部在某個表里面。在這就是order_tab_0上有全部數據,或是order_tab_1上有全部數據。
    在這里插入圖片描述
  • 偏移量中前面兩條全部在一張表,但是符合條件的數據在另外一張表
    在這里插入圖片描述
  • 偏移量和數據在兩張表都有
    在這里插入圖片描述
    在分庫分表中,一個SELECT語句生成的目標語句是這樣的:
SELECT * FROM order_tab ORDER BY id LIMIT 6 OFFSET 0
SELECT * FROM order_tab ORDER BY id LIMIT 6 OFFSET 0

注意看LIMIT部分,被修改成了0,6。通俗的說,如果一個分頁語句是 LIMIT x OFFSET y 的形式,那么最終生成的目標語句就是 LIMIT x + y OFFSET 0。

LIMIT x OFFSET y => LIMIT x+y OFFSET 0

當分庫分表中間件拿到這兩個語句的查詢結果之后,就要在內存里進行排序,再找出全局的LIMIT 4 OFFSET 2
可以先回答這種全局排序的思路,關鍵詞就是 LIMIT x + y OFFSET 0

分庫分表中間件一般采用的就是全局排序法。假如說我們要查詢的是LIMIT X OFFSET y,那么分庫分表中間件會把查詢改寫為LIMIT x+y OFFSET 0,然后把查詢請求發送給所有的目標表。在拿到所有的返回值后,在內存中排序,然后根據排序結果找出全局符合條件的目標數據。

接下來可以先從性能問題上刷一個亮點,抓住受影響的三個方面:網絡、內存和CPU

這個解決方案的最大問題就是性能不好。
首先是網絡傳輸瓶頸,比如在LIMIT 10 OFFSET 1000這種場景下,如果沒有分庫分表,只需要傳輸10條數據;在分庫分表的情況下,如果命中了N個表,那么需要傳輸的是(1000+10)*N條數據。而實際上最終我們只會用其中的10條數據,存在巨大的浪費。
其次是內存瓶頸。收到那么多數據之后,中間件需要維持在內存中排序。
CPU也會成為瓶頸,因為排序本身是一個CPU密集的操作。所以在Proxy形態的分庫分表中間件里,分頁查詢一多,就容易把中間件的內存耗盡,引發OOM,又或是CPU 100%。
不過可以通過歸并排序來緩解這些問題。

關鍵在拿到數據之后,使用歸并排序的算法。

在分庫分表里,可以使用歸并排序算法來給返回的結果排序,也就是說在改寫為LIMIT x+y OFFSET 0之后,每個目標表返回的結果都是有序的,自然可以使用歸并排序。在歸并排序的過程中,我們可以逐條從返回結果中讀取,這意味著沒必要將所有的結果一次性放到內存中再排序。在分頁的場景下,取夠了數據可以直接返回,剩下的數據就可以丟棄了

在這里插入圖片描述
前面說了全局查詢這個方案的性能很差,那么有沒有其他方案呢?
的確有,比如平均分頁、禁用跨頁查詢、換用其他中間件等。不過任何方案都不是十全十美的,這些方案也存在一些難點,有的是需要業務折中,有的處理過程非常復雜。我們先來看第一個需要業務折中的平均分頁方案

優化方案1:平均分頁

看到分頁查詢的第一個念頭應該是:能不能在不同的表上平均分頁查詢數據,得到的結果合并在一起就是分頁的結果
例如,查詢中的語句是這樣的

SELECT * FROM order_tab ORDER BY id LIMIT 4 OFFSET 2

因為本身有兩張表,可以改成這樣

SELECT * FROM order_tab_0 ORDER BY id LIMIT 2 OFFSET 1
SELECT * FROM order_tab_1 ORDER BY id LIMIT 2 OFFSET 1

在每一張表都查詢從偏移量1開始的2條數據,那么合并在一起就可以認為從全局的偏移量2開始的4條數據。
在這里插入圖片描述圖里我們能夠看出來,按照道理全局的 LIMIT 4 OFFSET 2 拿到的應該是 3、4、5、6 四條數據。但是這里我們拿到的數據卻是 2、4、5、9。這也就是這個方案的缺陷:它存在精度問題。也就是說,它返回的數據并不一定是全局最精確的數據

那么這個方案是不是就不能用了呢?并不是的,在一些對順序、精度要求不嚴格的場景下,還是可以用的。例如瀏覽頁面,你只需要返回足夠多的數據行,但是這些數據具體來自哪些表,用戶并不關心。
關鍵詞就是平均分頁

在一些可以接受分頁結果不精確的場景下,可以考慮平均分頁的做法。舉個例子來說,如果查詢的是 LIMIT 4 OFFSET 2,并且命中了兩張目標表,那么就可以考慮在每個表上都查詢 LIMIT 2 OFFSET 1。這些結果合并在一起就是 LIMIT 4 OFFSET 2 的一個近似答案。這種做法對于數據分布均勻的分庫分表效果很好,偏差也不大

這個方案還有一個進階版本,就是根據數據分布來決定如何取數據。

更加通用的做法是根據數據分布來決定分頁在不同的表上各自取多少條數據。比如說一張表上面有 70% 的數據,但是另一張表上只有 30% 的數據,那么在 LIMIT 10 OFFSET 100 的場景下,可以在 70% 的表里取 LIMIT 7 OFFSET 70,在 30% 的表里取 LIMIT 3 OFFSET 30。所以,也可以把前面平均分配的方案看作是各取 50% 的特例

那如何知道一張表上有70%的數據,另外一張表上有30%。
在開發的時候先用SQL在不同的表上執行一下,看看同樣的WHERE條件下各自返回了多少數據,就可以推斷出來了。
不過實際上,能夠接受不精確的業務場景還是比較少的。所以我們還有一種業務折中的解決方案,它精確并且高效,也就是禁用跨頁查詢方案。

優化方案2:禁用跨頁查詢

只允許用戶從第0頁開始,逐頁往后翻,不允許跨頁。
假如業務上分頁查詢是50條數據一頁,那么發起的查詢依次是:

SELECT * FROM order_tab ORDER BY id LIMIT 50 OFFSET 0
SELECT * FROM order_tab ORDER BY id LIMIT 50 OFFSET 50
SELECT * FROM order_tab ORDER BY id LIMIT 50 OFFSET 100
...

不斷增長的只有偏移量,如何控制住這個偏移量呢?
答案是根據ORDER BY的部分來增加一個查詢條件。上述例子里的order by是根據id升序排序的,只需要在where部分增加一個大于上次查詢的最大id的條件就可以了。max_id 是上一批次的最大id

SELECT * FROM order_tab WHERE `id` > max_id ORDER BY id LIMIT 50 OFFSET 0

即使order by里使用了多個列,規則也是一樣的

總體來看,回答要分成兩部分,第一部分介紹基本做法,關鍵詞是拿到上一批次的極值

目前比較好的分頁做法是禁用跨頁查詢,然后在每一次查詢條件里加上上依次查詢的極值,也就是最大值或者最小值。比如說第一次查詢的時候ORDER BY ID LIMIT 10 OFFSET 0,那么下一頁就可以改為WHERE id > max_id ORDER BY ID LIMIT 10 OFFSET 0。在現在的手機 App 里這個策略是非常好用的,因為手機 App 都是下拉刷新,天然就不存在跨頁的問題。

第一部分提到了極值,面試官可能問你什么時候用最大值,什么時候用最小值,可以這樣說:

至于用最大值還是最小值,取決于order by。總的原則就是升序用最大值,降序用最小值。如果order by里面包含了多個列,那么針對每一個列是升序還是降序,來確定使用最大值還是最小值。

這種方案并沒有徹底解決分庫分表查詢中的分頁問題,但是控制了偏移量,極大的減少了網絡通信的消耗和磁盤掃描的消耗。

優化方案3:換用中間件

一種思路是使用NoSQL之類的來存儲數據,比如使用Elasticsearch、ClickHouse;另一種思路是使用分布式關系型數據庫,相當于把分頁的難題拋給了數據庫

優化方案4:二次查詢(亮點)

先嘗試獲取某個數據的全局偏移量,再根據這個偏移量來計算剩下數據的偏移量。這里用一個例子來闡述它的基本原理,再抽象出一般步驟。
假設我們的查詢是

SELECT * FROM order_tab ORDER BY id LIMIT 4 OFFSET 4

數據分布如圖所示:
在這里插入圖片描述
全局的LIMIT 4 OFFSET 4 是 5、6、7、8 四條數據

步驟1:首次查詢

把SQL語句改寫成這樣:

SELECT * FROM order_tab_0 ORDER BY id LIMIT 4 OFFSET 2
SELECT * FROM order_tab_1 ORDER BY id LIMIT 4 OFFSET 2

我們只是把OFFSET平均分配了,但是LIMIT沒變
第一次查詢到的數據是這樣
在這里插入圖片描述order_tab_0 拿到了 4、6、10、12,而 order_tab_1 拿到了 7、8、9、11

步驟二:確認最小值

id最小的是4,來自order_tab_0

步驟三:二次查詢

這一次查詢需要利用上一步找出來的最小值以及各自分庫的最大值來構造BETWEEN查詢,改寫得到的SQL是:

SELECT * FROM order_tab_0 WHERE id BETWEEN 4 AND 12
SELECT * FROM order_tab_1 WHERE id BETWEEN 4 AND 11

結果:

  • order_tab_0 返回 4、6、10、12。
  • order_tab_1 返回 5、7、8、9、11,也就是多了 1 條數據,記住這一點。
    在這里插入圖片描述
    取過來的所有數據排序之后就是4、5、6、7、8、9、10、11、12

步驟四:計算最小值的全局偏移量

核心是:根據BETWEEN中多出來的數據量來推斷全局偏移量

現在我們知道4在order_tab_0中的偏移量是2,也就是說比4小的數據有2條。
在BETWEEN查詢里,order_tab_1返回的結果是5,7,8,9,11,其中7在第一次查詢里的偏移量是2,所以5的偏移量是1。也就是說,5的前面只有一條比4小的數據。
那么4在order_tab中的全局偏移量就是1+2=3,也就是4前面有三條數據。
在這里插入圖片描述
加上4本身,剛好構成了OFFSET 4,因此從5開始取,往后取4條數據。

總結

簡化版本:

  1. 首次查詢,拿到最小值
  2. 二次查詢,確實最小值的全局偏移量
  3. 在二次查詢的結果里根據最小值取到符合偏移量的數據

抽象版本:
假設分庫分表共有n個表,查詢是LIMIT X OFFSET Y,那么:

  1. 首先發送查詢語句 LIMIT X OFFSET Y/N 到所有的表
  2. 找到返回結果中的最小值(升序),記作min
  3. 執行第二次查詢,關鍵是BETWEEN min AND max,其中max是第一次查詢的數據中每個表各自的最大值
  4. 根據min、第一次查詢和第二次查詢的值來確定min的全局偏移量。總的來說,min在某個表里的偏移量這樣計算:如果第二次查詢比第一次查詢多了K條數據,偏移量就是Y/N-K。然后把所有表的偏移量加在一起,就是min的全局偏移量
  5. 根據min的全局偏移量,在第二次查詢的結果里面向后補足到Y,得到第一條數據的位置,再取X條。

優化方案5:引入中間表(亮點)

引入中間表的意思是額外存儲一份數據,只用來排序。這個方案里面就是在中間表里加上排序相關的列
在這里插入圖片描述

排序是一個非常常見的需求,那么就可以考慮引入一個中間表來輔助排序。比如說用更新時間來排序的時候,在中間表里加上更新時間。查詢的時候先在中間表里查到目標數據,再去目標表里把全部數據都查詢出來。
有兩個明顯的缺陷:一是WHERE只能使用中間表上的列;二是維護中間表也會引起數據一致性問題。

在這里插入圖片描述
那么如何解決數據一致性問題呢?

比較簡單的做法就是業務保持雙寫,也就是寫入目標表也寫入中間表。不過這里我更加建議使用 Canal 之類的框架來監聽 binlog,異步更新中間表。這樣做的好處是業務完全沒有感知,沒有什么改造成本。更新的時候可以考慮引入重試機制,進一步降低失敗的幾率。

面試官可能進一步問你,如果更新中間表經過重試之后也失敗了,怎么辦?
這時候并沒有更好的辦法,無非就是引入告警,然后人工介入處理。最后你可以再總結一下這個方案。

這個方案是一個依賴最終一致性的方案,在強調強一致性的場景下并不是很合適。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/45851.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/45851.shtml
英文地址,請注明出處:http://en.pswp.cn/web/45851.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Flutter】 webview_flutter避坑

webview_flutter webview_flutter沒有SSL Error接口,也就是說等你的網頁出現SSL 錯誤的時候這個插件無法捕捉處理,除非你改它的源碼。 下面這段是webview_flutter官網的例子,它有onHttpError、onWebResourceError、但沒有任何捕捉 SSL 錯誤…

代謝組數據分析(十五):基于python語言構建PLS-DA算法構建分類模型

介紹 本教程描述了一個具有二元分類結果的研究的典型代謝組學數據分析工作流程。主要步驟包括: 從Excel表格導入代謝物和實驗數據。基于匯總QC的數據清洗。利用主成分分析可視化來檢查數據質量。兩類單變量統計。使用偏最小二乘判別分析(PLS-DA)進行多變量分析,包括: 模型…

go語言 fmt的幾個打印區別以及打印格式

文章目錄 一、打印Print1.1 fmt.Print 和 fmt.Println1.2fmt.Printf1.3 fmt.Sprint, fmt.Sprintf, 和 fmt.Sprintln1.4 fmt.Fprint, fmt.Fprintf, 和 fmt.Fprintln 二、打印格式基本格式動詞整數類型浮點數和復數類型字符串和字節切片布爾類型指針 一、打印Print Go 語言的 fm…

字符串類中的常用方法

1 string對象的創建 靜態創建 String s1  "abc";  String s2  "abc";  動態創建 String s3  new String("abc"); String s4  new String("abc"); 2string對象的不可變性 任何一個String對象在創建之后都不能對它的…

大數據環境下的房地產數據分析與預測研究的設計與實現

1緒論 1.1研究背景及意義 隨著經濟的快速發展和城市化進程的推進,房地產市場成為了國民經濟的重要組成部分。在中國,房地產行業對經濟增長、就業創造和資本投資起到了重要的支撐作用。作為中國西南地區的重要城市,昆明的房地產市場也備受關…

云備份服務端

文件使用工具和json序列化反序列化工具 //文件和json工具類的設計實現 #ifndef __UTIL__ #define __UTIL__ #include<iostream> #include<fstream> #include<string> #include <vector> #include<sys/stat.h> #include"bundle.h" #inc…

FPGA資源容量

Kintex? 7 https://www.amd.com/zh-tw/products/adaptive-socs-and-fpgas/fpga/kintex-7.html#product-table AMD Zynq? 7000 SoC https://www.amd.com/en/products/adaptive-socs-and-fpgas/soc/zynq-7000.html#product-table AMD Zynq? UltraScale? RFSoC 第一代 AMD Z…

【每日一練】python類的構造方法以及常用的魔術方法詳細講解

在Python中&#xff0c;構造方法是一個用來初始化新創建的對象狀態的特殊方法。Python中的構造方法是__init__。此外&#xff0c;Python中的"魔術方法"是Python提供的一系列特殊方法&#xff0c;它們都以雙下劃線開頭和結尾&#xff0c;例如__init__, __str__, __rep…

Redis系列命令更新--Redis列表命令

Redis列表 1、Redis Blpop命令&#xff1a; &#xff08;1&#xff09;說明&#xff1a;Redis Blpop命令移出并獲取列表的第一個元素&#xff1b;如果列表沒有元素會阻塞列表直到等到超時或發現可彈出元素為止 &#xff08;2&#xff09;語法&#xff1a;redis 127.0.0.1:63…

mybaits-plus自定義分頁查詢

1. 引入依賴 在 pom.xml 文件中添加必要的依賴&#xff1a; <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId&…

Git進階(十四):Windows下 git 提示 Repository not found

文章目錄 一、前言 一、前言 在Windows10下執行 git clone/pull 的時候出現Repository not found錯誤。解決方法如下&#xff1a; 打開控制面板 搜索“憑據” 選中“Windows憑據” 在“普通憑據”一欄中查看當前git服務器配置的憑據信息是否正確&#xff0c;出現以上問題的…

081、Python 關于方法重寫

所謂方法重寫&#xff0c;就是子類對父類已有的方法&#xff0c;重新編寫自己的實現版本&#xff0c;這個過程就叫做方法重寫&#xff08;override&#xff09;。 說到方法重寫&#xff0c;就不得不提多態。因為方法重寫是實現多態的一種重要方式。 所謂多態&#xff0c;就是…

Windows的包管理器Chocolatey

Chocolatey 是 Windows 平臺上的一個軟件包管理工具&#xff0c;類似于 Linux 上的 apt、yum 或者 macOS 上的 Homebrew。你可以通過命令行快速安裝、更新和卸載軟件包。 一、安裝 Chocolatey 查看是否有安裝 choco --version 2.3.0如果有顯示版本號&#xff0c;說明安裝成功…

Laravel IDE Helper:開發者的代碼導航燈塔

Laravel IDE Helper&#xff1a;開發者的代碼導航燈塔 在Laravel開發過程中&#xff0c;IDE&#xff08;集成開發環境&#xff09;的輔助工具可以極大地提高開發效率和代碼質量。Laravel IDE Helper是一個專門為此目的設計的工具&#xff0c;它為PHP IDE提供了額外的上下文信息…

提高自動化測試腳本編寫效率 5大關鍵注意事項

提高自動化測試腳本編寫效率能加速測試周期&#xff0c;減少人工錯誤&#xff0c;提升軟件質量&#xff0c;促進項目按時交付&#xff0c;增強團隊生產力和項目成功率。而自動化測試腳本編寫效率低下&#xff0c;往往會導致測試周期延長&#xff0c;增加項目成本&#xff0c;延…

Python項目部署到Linux生產環境(uwsgi+python+flask+nginx服務器)

1.安裝python 我這里是3.9.5版本 安裝依賴&#xff1a; yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make -y 根據自己的需要下載對應的python版本&#xff1a; cd local wget https://www.python.org/ftp…

git 提交遠程倉庫 方式

第一種方式&#xff1a; git init //初始化 gitgit clone https://github.com/luckygilrhpp/gitTest.git //克隆遠程倉庫代碼將要提交的文件夾復制到這個clone的遠程倉庫里面 第二種方式&#xff1a; git init git remote add origin https://github.com/lucky…

高性能存儲 SIG 月度動態:優化 xfs dax reflink 時延,獨立選型并維護 mdadm 和 ledmon

本次高性能存儲月度動態綜合了 SIG 在 5、6 兩個月的工作進展&#xff0c;包含多項特性支持&#xff0c;性能優化&#xff0c;以及 Bugfix 等。 01 SIG 整體進展 引入 xfs deferred inode inactivation&#xff0c;進一步優化 xfs dax reflink 過程中的抖動時延。 Intel 將在…

UE5.4新功能 - MotionDesign上手簡介

MotionDesign是UE中集成的運動圖形功能&#xff0c;我們在游戲中經常會見到&#xff0c;例如前方漂浮于空中的若干碎石&#xff0c;當玩家走進時碎石自動吸附合并變成一條路&#xff0c;或者一些裝飾性的物件做隨機運動等等&#xff0c;在引擎沒有集成運動圖形時&#xff0c;這…

網絡爬蟲開發:JavaScript與Python特性的小差異

JavaScript JavaScript具有以下一些主要特點&#xff1a; 動態類型&#xff1a; JavaScript是一種動態類型語言&#xff0c;變量可以存儲任意類型的數據&#xff0c;無需事先聲明變量的類型。事件驅動&#xff1a;JavaScript主要用于處理用戶在瀏覽器中的各種交互事件&#x…