各个数据库存二进制大文件的性能测试
1前言
? 有個(gè)項(xiàng)目軟件前端將二進(jìn)制大文件存在了indexDB,每次給后端傳文件(需要傳到底層C++進(jìn)行調(diào)用)都會(huì)導(dǎo)致內(nèi)存占用飆升,想著使用前后端都能共同操作的數(shù)據(jù)庫(kù)來(lái)解決這個(gè)內(nèi)存占用的問(wèn)題,并且希望這個(gè)更具盡可能的輕量,可以嵌入到程序中是最好的,通過(guò)一個(gè)安裝包進(jìn)行安裝。
2各個(gè)數(shù)據(jù)庫(kù)的性能比較
2.1 MySQL
? 預(yù)先準(zhǔn)備35MB的Byte數(shù)組數(shù)據(jù),將其存到數(shù)據(jù)庫(kù)的格式為blob,測(cè)試MySQL存儲(chǔ)100塊35MB的數(shù)據(jù)需要300秒,平均一塊需要3s時(shí)間。
2.2 MongoDB
? MongoDB的數(shù)據(jù)是采用鍵值對(duì)的形式進(jìn)行存儲(chǔ),一樣是采用100塊35MB的數(shù)據(jù)進(jìn)行寫(xiě)入,測(cè)試需要45s時(shí)間,平均一塊是450ms。
2.3 SQLite測(cè)試及優(yōu)化過(guò)程
2.3.1 概述
? SQLite使用Mybatis作為ORM框架進(jìn)行100塊35MB的寫(xiě)入速度,100塊使用了12s,平均一塊35MB寫(xiě)入速度是120ms,遠(yuǎn)快于前面兩種使用Mybatis讀數(shù)據(jù)庫(kù)blob格式出現(xiàn)不支持的問(wèn)題,將ORM換到JdbcTemplate后,支持blob格式,進(jìn)行讀,一塊35MB讀了40s時(shí)間,猜測(cè)是JdbcTemplate是比較落后的方案,沒(méi)有針對(duì)大文件優(yōu)化。
2.3.2 優(yōu)化流程
(一)表結(jié)構(gòu)優(yōu)化
? 主鍵id改為PrimaryKey,并且設(shè)置自增,使得每次都可以B+樹(shù)主鍵索引命中查詢內(nèi)容。
(二)Mybatis優(yōu)化
依然是換回springboot最主流的mybatis框架,手寫(xiě)mapper.xml文件處理blob格式,指定handler處理器編寫(xiě)對(duì)blob的處理,最終實(shí)現(xiàn)對(duì)blob的讀取。優(yōu)化后,對(duì)讀取的數(shù)據(jù)不進(jìn)行解析的話,平均一塊35MB的數(shù)據(jù)讀取50ms,涉及到數(shù)據(jù)解析(需要用byte數(shù)組接blob,并對(duì)整個(gè)數(shù)組中的數(shù)據(jù)解析取值)會(huì)再多一些時(shí)間。
(三)使用JPA
? Mybatis除了對(duì)blob數(shù)據(jù)讀取支持不好外,操作sqlite數(shù)據(jù)庫(kù)時(shí),使用自增id無(wú)法正常生成id的值,決定換到JPA進(jìn)行嘗試。
在JPA下,寫(xiě)100塊35MB的數(shù)據(jù)如下:
?
? 可見(jiàn)寫(xiě)入速度接近于Mybatis和JdbcTemplate,都是100+ms。
? 測(cè)試讀100塊35MB的數(shù)據(jù):
? 讀的速度得到很大提升,30ms左右,快于mybatis下的50ms。
? 在測(cè)試35塊100MB大小的數(shù)據(jù)的寫(xiě)操作:
? 寫(xiě)操作的時(shí)間基本成線性增長(zhǎng),100MB一塊寫(xiě)入需要400ms+。
? 再測(cè)試讀操作:
100MB的讀操作性能還是很高,讀一塊100MB大小的分塊是100+ms。(上述測(cè)試涉及到的讀操作都是沒(méi)有對(duì)數(shù)據(jù)進(jìn)行解析的)
(四)針對(duì)寫(xiě)過(guò)程進(jìn)行優(yōu)化
? 當(dāng)前場(chǎng)景下,需要不斷對(duì)數(shù)據(jù)庫(kù)執(zhí)行多個(gè)插入操作,默認(rèn)情況下,每次插入一個(gè)數(shù)據(jù)都會(huì)開(kāi)始事務(wù)和提交事務(wù),多次提交會(huì)重復(fù)這個(gè)流程,磁盤(pán)I/O頻率高,嘗試開(kāi)啟事務(wù),在數(shù)據(jù)都準(zhǔn)備好情況下再進(jìn)行提交事務(wù)。在插入的方法上加入注解@Transactional,下面測(cè)試有無(wú)@Transactional情況下存10個(gè)100MB數(shù)據(jù)的情況。
左邊是使用了注解后的結(jié)果,右邊是沒(méi)有,開(kāi)啟事務(wù)后提升是很明顯的。一塊100MB的分塊寫(xiě)入從400ms降低到300ms,但會(huì)導(dǎo)致另外一個(gè)問(wèn)題,如果35個(gè)100MB的數(shù)據(jù)同時(shí)存進(jìn)去會(huì)出現(xiàn)java堆溢出,因?yàn)檫@3.5g在事務(wù)commit前都是放在內(nèi)存里面導(dǎo)致溢出。
(五)針對(duì)讀過(guò)程嘗試進(jìn)行優(yōu)化
? 對(duì)讀過(guò)程嘗試調(diào)節(jié)了SQLite一些參數(shù),但是基本沒(méi)有提升。
設(shè)置PRAGMA synchronous = OFF,關(guān)閉寫(xiě)同步,PRAGMA synchronous = OFF,在 sqlite3 中 synchronous 有三種模式,分別是 FULL,NORMAL 和 OFF,在系統(tǒng)意外終止的時(shí)候,安全性逐級(jí)減弱,F(xiàn)ULL模式下,保證數(shù)據(jù)不會(huì)損壞,安全性最高,寫(xiě)入速度也最慢。
設(shè)置PRAGMA page_size = 8192,通過(guò)設(shè)置PAGE_SIZE參數(shù),調(diào)整最小存儲(chǔ)單元PAGE的大小,由于存入的數(shù)據(jù)較大,嘗試改成8192,甚至16384。
設(shè)置完沒(méi)有提升,猜測(cè)上面參數(shù)是針對(duì)數(shù)量條數(shù)很大的情況才有提升,當(dāng)前情況是數(shù)據(jù)條數(shù)不多,但單獨(dú)的每條數(shù)據(jù)占用內(nèi)存大。
2.4 LevelDB
? Leveldb也是輕量級(jí)數(shù)據(jù)庫(kù),屬于NOSQL,是以key-value形式進(jìn)行存儲(chǔ),Java和node.js都能同時(shí)使用,但是經(jīng)過(guò)測(cè)試,同樣存入35個(gè)100MB分塊大小的數(shù)據(jù),每一塊存入時(shí)間是400ms,每一塊讀取時(shí)間也接近400ms,相比較jpa下的sqlite表現(xiàn),并沒(méi)有提升。
2.5 IndexDB(原有方案)
? 讀100MB的分塊是50毫秒,讀性能非常的好。
寫(xiě)入100MB分塊的時(shí)候,算上json轉(zhuǎn)blob 以及入庫(kù)的時(shí)間,大概是100-200ms,時(shí)間遠(yuǎn)短于尚未做數(shù)據(jù)處理的sqlite(事務(wù)下300-400ms)。
3 結(jié)論
上述所測(cè)試的數(shù)據(jù)庫(kù)性能都不如原有方案下的indexDB,最接近indexDB的sqlite,讀寫(xiě)性能數(shù)據(jù)比較如下:
100MB分塊的寫(xiě)入,包括json數(shù)據(jù)解析,indexDB是100-200ms,sqlite不包括數(shù)據(jù)解析在開(kāi)啟事務(wù)的情況下是300-400ms,不開(kāi)啟事務(wù)則是400-500ms。
100MB分塊的讀取,不包括數(shù)據(jù)解析:indexDB是50ms,sqlite是100-200ms。
總結(jié)
以上是生活随笔為你收集整理的各个数据库存二进制大文件的性能测试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java监听全局组合键
- 下一篇: 【开源项目推荐】-支持GPT的智能数据库