當(dāng)開發(fā)與數(shù)據(jù)庫需要在一起使用的應(yīng)用程序時(shí),對象關(guān)系映射器(ORM)通常用于Python編程中。Python ORM的示例是SQLAlchemy,Peewee,Pony-ORM和Django。選擇ORM性能起著至關(guān)重要的作用。但是如何比較這些工具集?ORM性能基準(zhǔn)提供了明確的度量,但仍有很大的改進(jìn)空間。我研究并擴(kuò)展了定性的ORM基準(zhǔn),以幫助有需要開發(fā)需要的。定性的Python ORM基準(zhǔn)Tortoise ORM(鏈接到存儲庫)分析了11種SQL查詢的六個ORM的速度。
創(chuàng)新互聯(lián)建站服務(wù)項(xiàng)目包括漯河網(wǎng)站建設(shè)、漯河網(wǎng)站制作、漯河網(wǎng)頁制作以及漯河網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,漯河網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到漯河省份的部分城市,未來相信會繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!相關(guān)學(xué)習(xí)推薦:python視頻教程
通常,Tortoise基準(zhǔn)可以評估各種ORM的查詢執(zhí)行速度。但是,這種測試方法存在一個缺陷:大多數(shù)ORM被選擇用于Web應(yīng)用程序。在這種情況下,多個用戶經(jīng)常將所有形式的查詢發(fā)送到數(shù)據(jù)庫。因?yàn)樵谶@種情況下沒有評估的基準(zhǔn)測試工具能夠評估Python ORM的性能,所以我決定編寫自己的PonyORM和SQLAlchemy進(jìn)行比較。作為基礎(chǔ),我采用了TPC-C基準(zhǔn)。
自1988年以來,TPC一直在數(shù)據(jù)處理領(lǐng)域開發(fā)測試。它們早已成為行業(yè)標(biāo)準(zhǔn),幾乎所有設(shè)備供應(yīng)商都在各種硬件和軟件樣本上使用它們。這些測試的主要特征是它們專注于在盡可能接近真實(shí)條件的巨大負(fù)載下進(jìn)行測試。
TPC-C模擬倉庫網(wǎng)絡(luò)。它包括五個同時(shí)執(zhí)行的各種類型和復(fù)雜性的事務(wù)的組合。該測試的目的是評估多個虛擬用戶同時(shí)訪問數(shù)據(jù)庫時(shí)事務(wù)處理的速度。
我決定使用適合此任務(wù)的TPC-C測試方法測試兩個Python ORM(SQLALchemy和PonyORM)。該測試的目的是評估多個虛擬用戶同時(shí)訪問數(shù)據(jù)庫時(shí)事務(wù)處理的速度。
測試說明
第一步是創(chuàng)建并填充倉庫網(wǎng)絡(luò)的數(shù)據(jù)庫。
該數(shù)據(jù)庫包含八個關(guān)系:
1. 倉庫
2. 區(qū)
3. 訂購
4. 訂單行
5. 股票
6. 項(xiàng)目
7. 顧客
8. 歷史
Pony和SQLAlchemy的數(shù)據(jù)庫是相同的。僅索引主鍵和外鍵。小A會自動創(chuàng)建這些索引。在SQLAlchemy中,我手動創(chuàng)建了它。
在測試過程中,幾種虛擬用戶將不同類型的事務(wù)發(fā)送到數(shù)據(jù)庫。每個事務(wù)包含幾個請求??偣灿形宸N類型的交易以不同的發(fā)生概率提交處理:
交易:
1. 新訂單-45%
2. 付款-43%
3. order_status-4%
4. 交付-4%
5. 股票水平-4%
發(fā)生交易的可能性與原始TPC-C測試中的相同。
但是,請記住,由于技術(shù)上的限制以及我想測試以下處理器的性能,因此在具有64 GB以上RAM(需要大量處理器和巨大磁盤空間)的服務(wù)器上進(jìn)行了原始TPC-C測試。 ORM而不是硬件抵抗巨大負(fù)載的能力,因此此測試有所簡化。
與TPC-C測試的主要區(qū)別如下:
主要區(qū)別:
1. 該測試運(yùn)行的虛擬用戶少于原始測試
2. 我的測試的表?xiàng)l目較少。例如:原始測試中“庫存”關(guān)系中的條目數(shù)是使用公式100,000 * W計(jì)算的,其中W是倉庫數(shù)。在此測試中為100 *W。
3. 在TPC-C中,某些事務(wù)具有從數(shù)據(jù)庫查詢數(shù)據(jù)的多個選項(xiàng)。例如,在支付交易中,有一種可能性,將通過ID從數(shù)據(jù)庫中請求客戶,而另一種則是由姓和名。目前,我的測試僅按ID撥打電話。
4. 我的測試數(shù)據(jù)庫比TPC-C少一個表。在TPC-C測試中,創(chuàng)建訂單后,會將其添加到Order表和NewOrder表中。訂單交付后,便從NewOrder表中將其刪除。每分鐘應(yīng)用大量事務(wù)時(shí),這可以加快工作速度;但是由于我訪問數(shù)據(jù)庫的用戶較少,所以這是不必要的。相反,在Order表中,我添加了bool屬性“ is_o_delivered”,該屬性將為False,直到交付訂單為止。
接下來,我將簡要描述每個事務(wù)的作用。
交易次數(shù)
新命令
1. 將兩個參數(shù)傳遞給事務(wù):倉庫ID和客戶ID
2. 使用傳遞的ID從數(shù)據(jù)庫中選擇倉庫和客戶
3. 從數(shù)據(jù)庫中隨機(jī)選擇一個倉庫區(qū)域
4. 生成指示訂單行數(shù)的隨機(jī)數(shù)。
5. 創(chuàng)建一個Order對象
6. 循環(huán)創(chuàng)建OrderLine對象。在循環(huán)的每次迭代中,從項(xiàng)目表中選擇一個隨機(jī)項(xiàng)目
7. 更改訂單中每個項(xiàng)目的庫存
付款
1. 將兩個參數(shù)傳遞給事務(wù):倉庫ID和客戶ID
2. 通過傳遞的ID從數(shù)據(jù)庫中選擇倉庫和客戶
3. 從數(shù)據(jù)庫中隨機(jī)選擇一個倉庫區(qū)域
4. 生成一個指示付款金額的隨機(jī)數(shù)
5. 按付款金額增加倉庫和區(qū)域的余額
6. 客戶余額減少付款金額
7. 遞增客戶付款柜臺
8. 客戶付款金額的總和增加
9. 創(chuàng)建歷史記錄對象
訂單狀態(tài)
1. 傳遞客戶ID作為交易的參數(shù)
2. 通過ID和該客戶的最后訂單選擇客戶
3. 從訂單中獲取訂單狀態(tài)和訂單行。
交貨
1. 傳遞倉庫ID作為交易參數(shù)
2. 從數(shù)據(jù)庫中選擇倉庫及其所有區(qū)域
3. 為每個地區(qū)選擇最舊的未交付訂單。
4. 對于每個將交貨狀態(tài)更改為True的訂單
5. 對于每個訂單數(shù)量遞增的客戶
庫存水平
1. 傳遞倉庫ID作為交易參數(shù)
2. 通過ID從數(shù)據(jù)庫中選擇倉庫
3. 選擇該倉庫的最后20個訂單
4. 對于訂單中的每個項(xiàng)目,評估項(xiàng)目的庫存水平
檢測結(jié)果
有兩個ORM參與測試:
1. SQLAlchemy(圖形上的藍(lán)線)
2. PonyORM(圖形上的橙色線)
以下是通過2個并行進(jìn)程訪問數(shù)據(jù)庫運(yùn)行測試10分鐘的結(jié)果。使用“多重處理”模塊啟動流程。
X軸-時(shí)間(以分鐘為單位)
Y軸-已完成的交易數(shù)
作為DBMS,我使用PostgreSQL
所有交易
首先,按照TPC-C測試中的預(yù)期,我對所有五個事務(wù)進(jìn)行了測試。這項(xiàng)測試的結(jié)果是,小A的速度大約是以前的兩倍。
平均速度:
· 小A-2543筆交易/分鐘
· SQLAlchemy-1353.4事務(wù)/分鐘
之后,我決定分別評估五筆交易中ORM的性能。以下是每筆交易的結(jié)果。
新命令
平均速度:
· 小A-3349.2交易/分鐘
· SQLAlchemy-1415.3事務(wù)/分鐘
付款
平均速度:
· 小A-7175.3事務(wù)/分鐘
· SQLAlchemy-4110.6事務(wù)/分鐘
訂單狀態(tài)
平均速度:
· 小A-16645.6交易/分鐘
· SQLAlchemy-4820.8事務(wù)/分鐘
交貨
平均速度:
· SQLAlchemy-716.9事務(wù)/分鐘
· 小A-323.5交易/分鐘
庫存水平
平均速度:
· 小A-677.3交易/分鐘
· SQLAlchemy-167.9事務(wù)/分鐘
測試結(jié)果分析
收到結(jié)果后,我分析了為什么會這樣,并得出以下結(jié)論:
在5分之4的事務(wù)中,PonyORM的速度更快,因?yàn)樵谏蒘QL代碼時(shí),PonyORM會記住將Python表達(dá)式轉(zhuǎn)換為SQL的結(jié)果。因此,Pony不會在重復(fù)查詢時(shí)再次轉(zhuǎn)換該表達(dá)式,而SQLAlchemy在每次需要執(zhí)行查詢時(shí)都被強(qiáng)制生成SQL代碼。
Pony中此類查詢的示例:
stocks = select(stock for stock in Stock if stock.warehouse == whouse and stock.item in items).order_by(Stock.id).for_update()
生成的SQL:
SELECT “stock”.”id”, “stock”.”warehouse”, “stock”.”item”, “stock”.”quantity”, “stock”.”ytd”, “stock”.”order_cnt”, “stock”.”remote_cnt”, “stock”.”data”FROM “stock” “stock”WHERE “stock”.”warehouse” = %(p1)s AND “stock”.”item” IN (%(p2)s, %(p3)s)ORDER BY “stock”.”id”FOR UPDATE {‘p1’:7, ‘p2’:7, ‘p3’:37} SQLAlchemy: stocks = session.query(Stock).filter( Stock.warehouse == whouse, Stock.item.in_( items)).order_by(text(“id”)).with_for_update()
生成的SQL:
SELECT stock.id AS stock_id, stock.warehouse_id AS stock_warehouse_id, stock.item_id AS stock_item_id, stock.quantity AS stock_quantity, stock.ytd AS stock_ytd, stock.order_cnt AS stock_order_cnt, stock.remote_cnt AS stock_remote_cnt, stock.data AS stock_dataFROM stockWHERE stock.warehouse_id = %(warehouse_id_1)s AND stock.item_id IN (%(item_id_1)s, %(item_id_2)s) ORDER BY id FOR UPDATE {‘warehouse_id_1’: 7, ‘item_id_1’: 53, ‘item_id_2’: 54}
但是,顯然,SQLAlchemy可以更快地執(zhí)行交付類型事務(wù),因?yàn)樗梢詫?yīng)用于不同對象的多個UPDATE操作組合到一個命令中。
例:
INFO:www.zpedu.com/sqlalchemy.engine.base.Engine:UPDATE order_line SET delivery_d=% (delivery_d)s WHERE order_line.id = %(order_line_id)s INFO:sqlalchemy.engine.base.Engine:( {‘delivery_d’: datetime.datetime(2020, 4, 6, 14, 33, 6, 922281), ‘order_line_id’: 316}, {‘delivery_d’: datetime.datetime(2020, 4, 6, 14, 33, 6, 922272), ‘order_line_id’: 317}, {‘delivery_d’: datetime.datetime(2020, 4, 6, 14, 33, 6, 922261))
在這種情況下,小A會為每個更新發(fā)送單獨(dú)的查詢。
結(jié)論
根據(jù)測試的結(jié)果,我可以說Pony從數(shù)據(jù)庫中選擇的速度更快。另一方面,在某些情況下,SQLAlchemy可以以更高的速度生成Update類型的查詢。
分享文章:基于TPC-C基準(zhǔn)的PythonORM的性能測試詳解
文章來源:http://weahome.cn/article/cjeejd.html