TPC-C too simple?一文詳解 TPC-E:TPC-C 的升級版
從 TPC-C 到 TPC-E
在數(shù)據(jù)庫評測領(lǐng)域, TPC-C 可能是最出名的OLTP 基準(zhǔn)測試(benchmark)之一了。各大數(shù)據(jù)庫產(chǎn)品為展現(xiàn)其性能強大,紛紛在 TPC-C 性能榜上你方唱罷我登場。Oracle 一度獨占鰲頭,阿里 OceanBase、 騰訊 TD-SQL 也輪番登頂。達(dá)夢、TiDB、TBase 等等也紛紛用 TPC-C 作為自身產(chǎn)品的性能衡量標(biāo)準(zhǔn)。不僅如此,TPC-C 也在許多下游任務(wù)中頻繁亮相,例如參數(shù)調(diào)優(yōu)任務(wù)、負(fù)載預(yù)測任務(wù)、索引推薦任務(wù)等等。
然而,TPC-C 作為一個1992 年推出的 OLTP benchmark,庫表結(jié)構(gòu)、事務(wù)類型、業(yè)務(wù)場景都顯得“過于簡單”了。為了應(yīng)對數(shù)據(jù)庫領(lǐng)域的發(fā)展,TPC 委員會在 2007 年推出了下一代 OLTP 基準(zhǔn)測試:TPC-E。
在 TPC-E 官網(wǎng) 上,官方開宗明義:「TPC-E 比」 「TPC-C」 「更加復(fù)雜,因為它的事務(wù)類型更多樣化、庫表結(jié)構(gòu)和執(zhí)行結(jié)構(gòu)更復(fù)雜」:
?
TPC-E is more complex than previous OLTP benchmarks such as TPC-C because of its diverse transaction types, more complex database and overall execution structure.
?
TPC-E 相比 TPC-C 的復(fù)雜性是顯而易見的,我們僅列舉一些:
TPC-C | TPC-E | |
模擬場景 | 簡單的批發(fā)商系統(tǒng) | 復(fù)雜的證券交易所系統(tǒng) |
事務(wù)類型 | 5 種 | 12 種 |
庫表 | 9 張表 | 33 張表 |
數(shù)據(jù)生成 | 隨機數(shù),均勻分布 | 真實數(shù)據(jù)規(guī)律,有傾斜(skew) |
復(fù)雜 join | 最多 2 表 join | 最多 7 表 join |
讀寫比 | 1.9:1 | 9.7:1(讀負(fù)載比例更高) |
相比 TPC-C 威名赫赫,TPC-E 由于其復(fù)雜而顯得小眾,在工業(yè)界和學(xué)術(shù)界并沒有被廣泛地用于性能測試。然而在 TPC-C 已經(jīng)被研究透徹、各大廠商的評測中紛紛“過度優(yōu)化”的如今,TPC-E 基準(zhǔn)測試不失為一種新的、良好的補充。
本文接下來你會看到:
- 「概覽全貌」:對 TPC-E 做一份詳細(xì)的講解,展現(xiàn) TPC-E 的場景、庫表與事務(wù)全貌。
- 「實踐挑戰(zhàn)」:借助 “MySQL 索引優(yōu)化” 這一場景,展現(xiàn) TPC-E 對現(xiàn)有技術(shù)帶來的新的挑戰(zhàn)。
- 「原理解析」:深入SQL 級別,完全拆解 TPC-E 的 12 種事務(wù)類型,知其然也知其所以然。
- 「輕松上手」:繞過 Github 暗坑,在 MySQL 上編譯和運行 TPC-E。
概覽全貌
TPC-E 的場景是股票交易,涉及客戶、經(jīng)紀(jì)行和市場三種角色的復(fù)雜交互
TPC-E(Transaction Processing Performance Council - E)是一個模擬復(fù)雜在線交易處理(OLTP)環(huán)境的基準(zhǔn)測試。它通過一系列事務(wù)來模擬一個股票經(jīng)紀(jì)行的日常業(yè)務(wù)活動,這些活動涉及客戶賬戶管理、交易執(zhí)行以及與金融市場的互動。整個業(yè)務(wù)場景中包含了客戶、經(jīng)紀(jì)商、市場數(shù)據(jù)和后臺處理等關(guān)鍵要素。
這里我們從角色(Role)、事務(wù)和關(guān)系表三部分來展現(xiàn) TPC-E 全貌。
3種角色
TPC-E 模擬的是證券交易所,證券交易的買賣過程會涉及到下面三種角色:
- 「Brokerage(經(jīng)紀(jì)行)」 :在 TPC-E 基準(zhǔn)測試中,經(jīng)紀(jì)行的角色通常由
Customer Emulator
(客戶模擬器)組件扮演。它模擬了客戶與經(jīng)紀(jì)行的交互,包括提交交易請求、查詢賬戶信息、執(zhí)行市場分析等。經(jīng)紀(jì)行角色負(fù)責(zé)處理客戶的交易訂單,管理客戶賬戶,并提供市場數(shù)據(jù)。
- 注意,事務(wù)有一種類別是 Brokerage initiated,但代碼中并沒有單獨的 broker emulator,因為 broker 通常是應(yīng)答customer 的要求,broker 參與的事務(wù)就放到 CE 中模擬
- 「Customer(客戶)」 :客戶角色代表了實際使用經(jīng)紀(jì)行服務(wù)的個人或機構(gòu)投資者。在 TPC-E 中,客戶角色通過
Customer Emulator
組件模擬,執(zhí)行各種交易活動,如買賣證券、查詢持倉情況、查看市場動態(tài)等。客戶角色的目的是評估經(jīng)紀(jì)行提供的服務(wù)和交易平臺的性能。 - 「Market(市場)」 :市場角色在 TPC-E 中由
Market Exchange Emulator
(市場交易所模擬器)組件扮演。它模擬了股票市場的實際運作,包括股票價格的變動、交易的執(zhí)行、市場數(shù)據(jù)的發(fā)布等。市場角色為經(jīng)紀(jì)行和客戶提供了交易的場所和必要的市場信息。
這三個角色在 TPC-E 中的主要區(qū)別在于它們在交易過程中的職責(zé)和功能。經(jīng)紀(jì)行負(fù)責(zé)處理交易和客戶賬戶,客戶負(fù)責(zé)發(fā)起交易和查詢,而市場則提供了交易發(fā)生的環(huán)境和數(shù)據(jù)。
12 種事務(wù):一個故事
TPC-E 共包含了 12 種類型的事務(wù),為了便于理解,讓我們用一個故事串講一下。
在一個充滿活力的交易日,客戶們忙碌地通過經(jīng)紀(jì)行的交易平臺進(jìn)行股票買賣。他們首先會檢查自己的賬戶情況,了解自己的資產(chǎn)和持倉(Customer-Position
事務(wù)),然后根據(jù)市場動態(tài)(Market-Feed
事務(wù))和特定證券的詳細(xì)信息(Security-Detail
事務(wù))來制定交易策略。在做出決策之前,他們可能會監(jiān)控市場趨勢(Market-Watch
事務(wù)),或者回顧過去的交易記錄(Trade-Lookup
事務(wù)),以分析證券的歷史表現(xiàn)。經(jīng)紀(jì)行管理者會生成不同經(jīng)紀(jì)商的交易報告,用于評估各個經(jīng)紀(jì)商的表現(xiàn)(Broker-Volume
事務(wù))。一旦客戶決定買賣某只股票,他們會下達(dá)交易指令(Trade-Order
事務(wù))。這些指令會被提交到市場交易所,并在交易完成后收到交易結(jié)果(Trade-Result
事務(wù))。這些結(jié)果包括了交易的最終確認(rèn)、成交價格以及可能的稅務(wù)影響??蛻艨梢酝ㄟ^查看交易狀態(tài)(Trade-Status
事務(wù))來跟蹤他們的交易是否成功執(zhí)行。在交易過程中,客戶可能會需要更新或修改他們的交易指令(Trade-Update
事務(wù))。同時,為了保持?jǐn)?shù)據(jù)的準(zhǔn)確性和最新性,經(jīng)紀(jì)行會定期進(jìn)行數(shù)據(jù)維護(hù)(Data-Maintenance
事務(wù)),包括更新客戶賬戶信息、稅務(wù)信息以及市場數(shù)據(jù)。在交易日結(jié)束時,經(jīng)紀(jì)行需要清理數(shù)據(jù)庫,取消任何未完成或錯誤的交易(Trade-Cleanup
事務(wù)),以確保第二天的交易能夠順利進(jìn)行。這個過程包括從數(shù)據(jù)庫中移除所有掛起的交易請求,更新交易歷史記錄,并確保所有交易數(shù)據(jù)都是最新的。
33 張關(guān)系表
TPC-E 共涉及 33 張表:
- 「Customer Tables」:9 張表,描述了與客戶相關(guān)的表,包括賬戶信息(
CUSTOMER_ACCOUNT
)、稅務(wù)信息(CUSTOMER_TAXRATE
)等。 - 「Broker Tables」:9 張表,與經(jīng)紀(jì)商相關(guān)的表,如經(jīng)紀(jì)商(
BROKER
)、現(xiàn)金交易(CASH_TRANSACTION
)、費用(CHARGE
)等。 - 「Market Tables」:11 張表,與市場相關(guān)的表,如公司(
COMPANY
)、每日市場數(shù)據(jù)(DAILY_MARKET
)、交易所(EXCHANGE
)等。 - 「Dimension Tables」:維度表,如地址(
ADDRESS
)、狀態(tài)類型(STATUS_TYPE
)、稅率(TAXRATE
)等。
TPC 委員會公布的 TPC-E 標(biāo)準(zhǔn)文件(pdf)中事無巨細(xì)的講解了 TPC-E 各方面內(nèi)容,其中2.2.4 ~ 2.2.7 描述庫表設(shè)計,感興趣的同學(xué)可以深入了解下:
衡量標(biāo)準(zhǔn):tpsE
TPC-E 衡量的標(biāo)準(zhǔn)是 tpsE(transactions- per-second-E,每秒成交量)。在 TPC-E 對真實場景的模擬中,用戶和經(jīng)紀(jì)商可能經(jīng)過許多次的觀望、選擇、評估,才會達(dá)成一筆交易。因此,TPC-E 的性能取決于 Trade-Result
事務(wù)完成的數(shù)量。例如,如果一個客戶執(zhí)行了一項交易,并且該交易被成功處理(即交易請求被接受并執(zhí)行,Trade-Result +
1),那么這將被視為完成了一個 tpsE。僅僅查看訂單或執(zhí)行其他非交易類型的操作通常不會計算在內(nèi)。Trade-Result
事務(wù)與全部事務(wù)的比例基本穩(wěn)定(例如 10%),也意味著 tpsE 基本可以反映數(shù)據(jù)庫執(zhí)行的事務(wù)總量??紤]到TPC-E
的事務(wù)通常較為復(fù)雜(單個事務(wù)會包含數(shù)十條 SQL),在我們執(zhí)行 TPC-E 測試時,盡管最終顯示的 tpsE 只有 100 上下,但實際執(zhí)行的
SQL 已經(jīng)超過數(shù)十萬條。
原理解析:深入 SQL 看事務(wù)
TPC-E 比 TPC-C 的復(fù)雜體現(xiàn)在事務(wù)的復(fù)雜。TPC-C 包含 5 種事務(wù),SQL 模板共 29 條,而 TPC-E 包含 12 種事務(wù),SQL 模板超過 120 條。在一些復(fù)雜的 TPC-E 事務(wù)中(例如 Trade-Order),包含 6 個階段(稱為 Frame),每個階段中會執(zhí)行多輪”子事務(wù)“。由此,在各種任務(wù)(參數(shù)調(diào)優(yōu)、規(guī)格調(diào)優(yōu)、索引推薦)走到深水區(qū)后,對事務(wù)細(xì)節(jié)的了解就很有必要了。
下面我們會逐一分析各個事務(wù)的事務(wù)邏輯概述和 SQL 細(xì)節(jié)。必要的地方我們會結(jié)合 TPCE 負(fù)載發(fā)生器的源碼進(jìn)行解析。
事務(wù)分類
TPC-E 的事務(wù)可以按照它們的功能和特征進(jìn)行分類。根據(jù)文檔中的描述,這些事務(wù)主要可以分為以下幾類:
- 「客戶發(fā)起的事務(wù)(Customer Initiated)」 :
這些事務(wù)模擬了客戶與系統(tǒng)交互的場景,如查詢賬戶信息、執(zhí)行交易等。
例如:Customer-Position(客戶持倉查詢)、Market-Watch(市場觀察)、一部分 Trade-Lookup(交易查詢)、Security-Detail(證券詳情查詢)、Trade-Order(交易委托)、Trade-Status(交易狀態(tài)查詢)、一部分 Trade-Update(交易更新)。
- 「經(jīng)紀(jì)商發(fā)起的事務(wù)(Brokerage Initiated)」
這些事務(wù)模擬了經(jīng)紀(jì)商內(nèi)部處理的場景,如生成報告、管理賬戶等。
例如:Broker-Volume(經(jīng)紀(jì)商成交量)。一部分 Trade-Lookup;一部分 Trade-Update
- 「市場觸發(fā)的事務(wù)(Market Triggered)」 :
這些事務(wù)模擬了市場活動對系統(tǒng)的影響,如市場數(shù)據(jù)更新、市場動態(tài)跟蹤等。
例如:Market-Feed(市場數(shù)據(jù)更新)、Trade-Result
- 「其他」:
Trade-Cleanup、Data-Maintenance
我們結(jié)合 Github 源碼進(jìn)行分析。tpce-mysql 中,DBConnection.h
文件包含幾個 enum,可以作為印證,如下:
/*
Customer Emulator System Under Test
由用戶
*/
enum eCESUTStmt
{
// Customer-Position 有2 階段、4 sql。文檔是3 階段(Frame),但第三階段只有 commit ,其他有意義的 sql 是對得上的。
CESUT_STMT_CPF1_1,
// Market-Watch(市場觀察)
CESUT_STMT_MWF1_1a,
// Security-Detail(證券詳情查詢)
CESUT_STMT_SDF1_1,
// Trade-Lookup(交易查詢),非常巨大的事務(wù)
CESUT_STMT_TLF1_1,
// Trade-Order(交易委托)
CESUT_STMT_TOF1_1,
//Trade-Status(交易狀態(tài)查詢)
CESUT_STMT_TSF1_1,
// Trade-Update(交易更新)
CESUT_STMT_TUF1_1,
}
/*
Market Exchange Emulator SUT
*/
enum eMEESUTStmt
{
// 極其巨大的事務(wù)
MEESUT_STMT_TRF1_1,
// Market-Feed(市場數(shù)據(jù)更新)
MEESUT_STMT_MFF1_1,
};
/*
Data Maintenance SUT
*/
enum eDMSUTStmt
{
// Trade-Cleanup,開測前初始化;
DMSUT_STMT_TCF1_2,
};
// 其他無對應(yīng)代碼 enum 的:
// Broker-Volume(經(jīng)紀(jì)商成交量):只有一個 frame、一句 sql,無 enum
除了上述分類,事務(wù)還可以根據(jù)它們的讀寫特性進(jìn)行區(qū)分:
- 「讀事務(wù)(Read-Only)」 :這類事務(wù)主要涉及數(shù)據(jù)的讀取,不會導(dǎo)致數(shù)據(jù)的修改。例如,客戶查詢賬戶信息(Customer-Position)或查看市場數(shù)據(jù)(Market-Watch)。
- 「讀寫事務(wù)(Read-Write)」 :這類事務(wù)既涉及數(shù)據(jù)的讀取也涉及數(shù)據(jù)的寫入,可能會改變數(shù)據(jù)庫的狀態(tài)。例如,執(zhí)行交易(Trade-Order)會創(chuàng)建新的交易記錄,更新客戶賬戶(Trade-Update)會改變賬戶的持倉信息。
- 「寫事務(wù)(Write-Only)」 :這類事務(wù)主要涉及數(shù)據(jù)的寫入,不涉及數(shù)據(jù)的讀取。例如,數(shù)據(jù)維護(hù)(Data-Maintenance)事務(wù)可能會更新或刪除數(shù)據(jù)庫中的記錄。
概括來看:
- 「Broker-Volume (BV)」 - 模擬「經(jīng)紀(jì)行」內(nèi)部業(yè)務(wù)處理,例如生成關(guān)于不同經(jīng)紀(jì)人業(yè)績、潛力的報告。
- 「Customer-Position (CP)」 - 模擬「客戶」查詢其賬戶的持倉情況。根據(jù)所有資產(chǎn)的當(dāng)前市場價值總結(jié)其賬戶價值。
- 「Market-Feed (MF)」 - 模擬跟蹤當(dāng)前市場活動,處理來自「市場交易所」的“股票行情”數(shù)據(jù)。
- 「Market-Watch (MW)」 - 允許「客戶」跟蹤一組證券的當(dāng)前日常趨勢(上漲或下跌),基于客戶的當(dāng)前持倉、觀察列表或特定行業(yè)。
- 「Security-Detail (SD)」 - 模擬「客戶」訪問特定證券(
Security
)的詳細(xì)信息,如進(jìn)行研究以決定是否執(zhí)行交易。 - 「Trade-Lookup (TL)」 - 模擬信息檢索,以回答關(guān)于一組交易的問題,可能涉及市場分析、交易歷史審查或特定客戶持倉分析。
- 「Trade-Order (TO)」 - 模擬「客戶、經(jīng)紀(jì)人」 或授權(quán)第三方購買或出售證券的過程,包括驗證授權(quán)、執(zhí)行市場價買賣、限價買賣以及提供財務(wù)影響估計。
- 「Trade-Result (TR)」 - 模擬完成股票市場交易的過程,更新客戶持倉,記錄交易結(jié)果和歷史信息。這是由 「market 市場交易所」 負(fù)責(zé)記錄的
- 「Trade-Status (TS)」 - 提供特定交易集合的狀態(tài)更新,模擬「客戶」查看其賬戶的最近交易活動摘要。
- 「Trade-Update (TU)」 - 模擬對一組交易進(jìn)行輕微修正或更新,類似于「客戶」或「經(jīng)紀(jì)人」審查交易并進(jìn)行小的編輯修正。
- 「Data-Maintenance (DM)」 - 模擬對主要靜態(tài)數(shù)據(jù)進(jìn)行定期修改,如更新參考數(shù)據(jù)。
- 「Trade-Cleanup (TC)」 - 用于取消數(shù)據(jù)庫中任何待處理或已提交的交易,通常在測試運行前將數(shù)據(jù)庫恢復(fù)到已知狀態(tài)。
Broker-Volume
「Broker-Volume 事務(wù)邏輯概述」 在 TPC-E 基準(zhǔn)測試的第 3.3.1 章節(jié)中,Broker-Volume 事務(wù)是一個典型的讀操作,它模擬了經(jīng)紀(jì)行內(nèi)部生成經(jīng)紀(jì)人業(yè)績報告的場景。這個事務(wù)的核心目標(biāo)是計算每個經(jīng)紀(jì)人在特定時間段內(nèi)的交易量,這通常涉及到對掛單限價訂單(TRADE_REQUEST)的匯總分析。
「SQL 細(xì)節(jié)」 Broker-Volume 事務(wù)的 SQL 查詢設(shè)計要實現(xiàn)以下目標(biāo):
- 「選擇經(jīng)紀(jì)人列表」:確定需要生成報告的經(jīng)紀(jì)人。
- 「檢索掛單限價訂單」:從 TRADE_REQUEST 表中檢索每個經(jīng)紀(jì)人的訂單信息。
- 「計算總交易量」:對每個經(jīng)紀(jì)人的訂單數(shù)量和價格進(jìn)行計算,得出總交易量。
- 「排序結(jié)果」:將經(jīng)紀(jì)人按照總交易量降序排列,以便展示業(yè)績最好的經(jīng)紀(jì)人。
以下是 Broker-Volume 事務(wù)的 SQL 偽代碼:
-- Broker-Volume 事務(wù)的 SQL 查詢
SELECT b_name, SUM(tr_qty * tr_bid_price) -- 經(jīng)紀(jì)人的總交易量
FROM trade_request, sector, industry, company, broker, security
WHERE tr_b_id = b_id -- 經(jīng)紀(jì)人表,通過經(jīng)紀(jì)人ID關(guān)聯(lián)
AND tr_s_symb = s_symb -- 行業(yè)表,通過證券符號關(guān)聯(lián)
AND s_co_id = co_id -- 行業(yè)表,通過行業(yè)ID關(guān)聯(lián)
AND co_in_id = in_id -- 確保公司表中的國家ID與行業(yè)表中的國家ID匹配
AND sc_id = in_sc_id -- 確保行業(yè)表中的公司ID與公司表中的ID匹配
AND b_name IN (%s..) -- 經(jīng)紀(jì)人名稱列表,這里 %s.. 是一個占位符,表示一系列經(jīng)紀(jì)人名稱
AND sc_name = '%s' -- 行業(yè)名稱,這里 '%s' 是一個占位符,表示特定的行業(yè)名稱
GROUP BY b_name
ORDER BY 2 DESC -- 按總交易量降序排列
在這個查詢中,我們使用了多個 JOIN 操作來關(guān)聯(lián)不同的表,確保我們能夠獲取每個經(jīng)紀(jì)人的交易請求信息。我們通過 WHERE 子句過濾出特定經(jīng)紀(jì)人和特定行業(yè)的交易請求。然后,我們使用 GROUP BY 對經(jīng)紀(jì)人名稱進(jìn)行分組,并計算每個經(jīng)紀(jì)人的總交易量。最后,我們使用 ORDER BY 對結(jié)果進(jìn)行降序排列,以便展示交易量最高的經(jīng)紀(jì)人。
Customer-Position
客戶位置(Customer-Position)由EGenDriverCE
調(diào)用。它由三個 frame 組成(frame 2和3是相互排斥的)。客戶由客戶ID(customer ID
)或客戶稅號(customer tax ID
)指定。如果轉(zhuǎn)入交易的 customer ID
為0,則使用客戶稅ID來查找客戶ID。檢索有關(guān)客戶個人資料的詳細(xì)信息。此外,對于每個客戶的賬戶,將退還該賬戶的現(xiàn)金余額和賬戶中所有持有的當(dāng)前市場總值。如果請求交易活動的歷史記錄,則檢索客戶帳戶中隨機選擇的帳戶的最新十筆交易的信息。
「事務(wù)邏輯概述」
Customer-Position 事務(wù)模擬了客戶查詢其賬戶持倉情況的場景。這個事務(wù)通過檢索客戶資料、賬戶余額、持倉詳情以及最近的交易歷史,為客戶提供了一個全面的賬戶狀態(tài)報告。在技術(shù)博客中,我們將詳細(xì)探討這個事務(wù)的每個階段,以及它們在 SQL 中的具體實現(xiàn)。
「Frame/sql 注解」
在 Frame 1 中,我們首先設(shè)置了事務(wù)的隔離級別為 READ COMMITTED,這確保了事務(wù)在讀取數(shù)據(jù)時的一致性。接著,我們執(zhí)行了兩個 SQL 查詢來獲取客戶信息。
-- 設(shè)置事務(wù)隔離級別
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 根據(jù)稅號查詢客戶ID
SELECT c_id FROM customer WHERE c_tax_id = _latin1'970AM8516RE955';
-- 獲取客戶詳細(xì)信息
SELECT
c_st_id, c_l_name, c_f_name, c_m_name, c_gndr, c_tier,
DATE_FORMAT(c_dob,'%Y-%m-%d'), c_ad_id,
c_ctry_1, c_area_1, c_local_1, c_ext_1,
c_ctry_2, c_area_2, c_local_2, c_ext_2,
c_ctry_3, c_area_3, c_local_3, c_ext_3,
c_email_1, c_email_2
FROM customer
WHERE c_id = 4300001491;
Frame 2 僅在 get_history
參數(shù)為 TRUE 時執(zhí)行。這個 Frame 負(fù)責(zé)檢索客戶最近的交易歷史。這里我們使用了兩個 SQL 查詢:
-- 查詢客戶賬戶的前10個持倉及其總價值
SELECT
ca_id, ca_bal, COALESCE(SUM(hs_qty * lt_price),0) AS price_sum
FROM
customer_account
LEFT OUTER JOIN holding_summary ON hs_ca_id = ca_id, last_trade
WHERE
ca_c_id = 4300001491 AND lt_s_symb = hs_symb
GROUP BY
ca_id, ca_bal
ORDER BY
price_sum ASC
LIMIT 10;
-- 查詢客戶最近的30條交易歷史記錄
SELECT
t_id, t_s_symb, t_qty, st_name, DATE_FORMAT(th_dts,'%Y-%m-%d %H:%i:%s.%f')
FROM
(SELECT t_id AS id FROM trade WHERE t_ca_id = 43000014904 ORDER BY t_dts DESC LIMIT 10) AS t,
trade, trade_history, status_type
FORCE INDEX(PRIMARY)
WHERE
t_id = id AND th_t_id = t_id AND st_id = th_st_id
ORDER BY
th_dts DESC
LIMIT 30;
Frame 3 包含了一個 COMMIT
語句,用于提交事務(wù),確保之前的所有更改都被保存到數(shù)據(jù)庫中。
-- 提交事務(wù)
COMMIT;
Market-Feed
「事務(wù)邏輯概述」
Market-Feed 事務(wù)在 TPC-E 基準(zhǔn)測試中扮演著模擬市場數(shù)據(jù)更新的角色。這個事務(wù)的目的是處理市場交易所的最新交易信息,這些信息通常包括股票的最后成交價格、成交量和成交時間。包含 1 個 frame
「Frame/sql 注解」 設(shè)置事務(wù)隔離級別
-- 設(shè)置事務(wù)隔離級別為可重復(fù)讀,確保在事務(wù)期間讀取的數(shù)據(jù)保持一致
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
更新最后成交信息
-- 更新 last_trade 表,模擬市場交易所的最新成交信息
UPDATE last_trade
SET
lt_price = '2.93399999999999999e+01', -- 設(shè)置最新的成交價格
lt_vol = lt_vol + '100', -- 增加成交量
lt_dts = '2024-02-27 20:48:17' -- 更新成交時間
WHERE
lt_s_symb = 'CLYS'; -- 指定特定的證券符號
查詢待處理的交易請求
-- 查詢 trade_request 表,找出與最新成交信息相關(guān)的待處理交易請求
SELECT
tr_t_id, tr_bid_price, tr_tt_id, tr_qty
FROM
trade_request
WHERE
tr_s_symb = 'CLYS' -- 指定證券符號
AND (
(tr_tt_id = 'TSL' AND tr_bid_price >= '2.93399999999999999e+01') -- 買入限價單,且報價大于等于最新成交價
OR (tr_tt_id = 'TLS' AND tr_bid_price <= '2.93399999999999999e+01') -- 賣出限價單,且報價小于等于最新成交價
OR (tr_tt_id = 'TLB' AND tr_bid_price >= '2.93399999999999999e+01') -- 買入止損單,且報價大于等于最新成交價
);
提交事務(wù)
-- 提交事務(wù),確保所有更改都被保存
COMMIT;
Market-Watch
Market-Watch 事務(wù)是由客戶執(zhí)行的,用于監(jiān)控市場的整體表現(xiàn)。這個事務(wù)通過比較選定證券集合在「特定日期的收盤價」與「當(dāng)前市場價格」的百分比變化來實現(xiàn)。這個集合可能基于客戶的當(dāng)前持倉、潛在證券觀察列表或特定行業(yè)。Market-Watch 事務(wù)包含 1 個 Frame,該 Frame 執(zhí)行一個 SQL 查詢來計算市值變化。
-- 設(shè)置事務(wù)隔離級別為 READ COMMITTED,確保事務(wù)在讀取數(shù)據(jù)時不會受到其他并發(fā)事務(wù)的影響
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 執(zhí)行查詢,計算市值變化
-- 這個查詢涉及到多個表的連接,包括 watch_item, watch_list, last_trade, security, 和 daily_market
-- 它計算了在特定日期('2004-12-31')的收盤價(dm_close)和當(dāng)前價格(lt_price)的總和
-- 通過比較這兩個總和,可以得到市值的百分比變化
SELECT
COALESCE(SUM(s_num_out * dm_close), 0) AS market_cap_change, -- 計算特定日期的市值
COALESCE(SUM(s_num_out * lt_price), 0) AS current_market_cap -- 計算當(dāng)前市值
FROM
watch_item,
watch_list,
last_trade,
security,
daily_market
WHERE
wl_c_id = '4300000678' -- 指定客戶ID
AND wi_wl_id = wl_id -- 確保 watch_item 和 watch_list 的關(guān)聯(lián)ID匹配
AND dm_s_symb = wi_symb -- 確保證券符號匹配
AND dm_date = '2004-12-31' -- 指定比較的日期
AND lt_s_symb = dm_s_symb -- 確保 last_trade 中的證券符號與 daily_market 中的匹配
AND s_symb = dm_s_sym; -- 確保 security 表中的證券符號與 daily_market 中的匹配
-- 關(guān)閉語句,結(jié)束查詢
Close stmt;
Security-Detail
「事務(wù)邏輯概述」
Security-Detail 事務(wù)旨在模擬客戶在決定是否執(zhí)行交易前對特定證券進(jìn)行詳細(xì)研究的過程。這個事務(wù)由 EGenDriverCE 觸發(fā),并且只包含 「1個 Frame」。事務(wù)會返回關(guān)于給定證券的詳細(xì)信息,包括公司信息、競爭對手列表、當(dāng)前和歷史財務(wù)數(shù)據(jù),以及關(guān)于公司的最新新聞條目。
「Frame/sql 注解」
-- 設(shè)置事務(wù)隔離級別為 READ COMMITTED,確保事務(wù)在讀取數(shù)據(jù)時的一致性
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 查詢證券和公司詳細(xì)信息
SELECT
s_name, co_id, co_name, co_sp_rate, co_ceo, co_desc,
DATE_FORMAT(co_open_date,'%Y-%m-%d'), co_st_id,
ca.ad_line1, ca.ad_line2, zca.zc_town, zca.zc_div, ca.ad_zc_code, ca.ad_ctry,
s_num_out, DATE_FORMAT(s_start_date,'%Y-%m-%d'),
DATE_FORMAT(s_exch_date,'%Y-%m-%d'), s_pe, s_52wk_high,
DATE_FORMAT(s_52wk_high_date,'%Y-%m-%d'), s_52wk_low,
DATE_FORMAT(s_52wk_low_date,'%Y-%m-%d'), s_dividend, s_yield,
zea.zc_div, ea.ad_ctry, ea.ad_line1, ea.ad_line2, zea.zc_town,
ea.ad_zc_code, ex_close, ex_desc, ex_name, ex_num_symb, ex_open
FROM
security, company, address ca, address ea, zip_code zca, zip_code zea, exchange
WHERE
s_symb = _latin1'XTRM'
AND co_id = s_co_id
AND ca.ad_id = co_ad_id
AND ea.ad_id = ex_ad_id
AND ex_id = s_ex_id
AND ca.ad_zc_code = zca.zc_code
AND ea.ad_zc_code = zea.zc_code;
-- 查詢公司競爭對手信息
SELECT
co_name, in_name
FROM
company_competitor, company, industry
WHERE
cp_co_id = 4300000566
AND co_id = cp_comp_co_id
AND in_id = cp_in_id
LIMIT 3;
-- 查詢公司財務(wù)數(shù)據(jù)
SELECT
fi_year, fi_qtr, DATE_FORMAT(fi_qtr_start_date,'%Y-%m-%d'),
fi_revenue, fi_net_earn, fi_basic_eps, fi_dilut_eps,
fi_margin, fi_inventory, fi_assets, fi_liability,
fi_out_basic, fi_out_dilut
FROM
financial
WHERE
fi_co_id = 4300000566
ORDER BY
fi_year ASC, fi_qtr
LIMIT 20;
-- 查詢證券市場歷史數(shù)據(jù)
SELECT
DATE_FORMAT(dm_date,'%Y-%m-%d'), dm_close, dm_high, dm_low, dm_vol
FROM
daily_market
WHERE
dm_s_symb = _latin1'XTRM'
AND dm_date >= _latin1'2000-08-12'
ORDER BY
dm_date ASC
LIMIT 15;
-- 查詢最后一筆交易信息
SELECT
lt_price, lt_open_price, lt_vol
FROM
last_trade
WHERE
lt_s_symb = _latin1'XTRM';
-- 查詢公司最新新聞條目
SELECT
DATE_FORMAT(ni_dts, '%Y-%m-%d %H:%i:%s.%f'), ni_source, ni_author, ni_headline, ni_summary
FROM
news_xref, news_item
WHERE
ni_id = nx_ni_id
AND nx_co_id = 4300000566
LIMIT 2;
-- 提交事務(wù),確保所有查詢結(jié)果被正確處理
COMMIT;
Trade-Lookup
Trade-Lookup包含 4 個 frame,實際上包含了多個數(shù)據(jù)庫意義上的“事務(wù)”,broker 和customer 分別執(zhí)行兩個 frame,這些甚至不在一個進(jìn)程中執(zhí)行完畢。因此不在通過 sql 解釋,而是概述其設(shè)計邏輯。
Trade-Lookup 事務(wù)是 TPC-E 基準(zhǔn)測試中的一個「關(guān)鍵組成部分」,它模擬了「客戶」或「經(jīng)紀(jì)人」為了回答關(guān)于一組交易的問題而進(jìn)行的信息檢索過程。這個事務(wù)涵蓋了多種場景,包括進(jìn)行市場分析
、回顧賬戶最近的交易記錄
、分析特定證券的過去表現(xiàn)
以及分析特定客戶持倉的歷史
。
Trade-Lookup 事務(wù)由 EGenDriverCE 觸發(fā),并且包含四個互斥的 Frame。每個 Frame 都采用不同的技術(shù)來查找歷史交易數(shù)據(jù)。
- 「Frame 1」 :Frame 1 接受一組交易 ID 的列表。對于列表中的每個交易 ID,系統(tǒng)會返回相關(guān)的交易信息。這允許用戶查詢特定的交易詳情,可能是為了驗證交易記錄或進(jìn)行詳細(xì)的交易分析。
- 「Frame 2」 :Frame 2 接受客戶賬戶 ID、開始時間戳、結(jié)束時間戳以及交易數(shù)量(N)作為輸入。它會返回在指定時間范圍內(nèi)(包括開始和結(jié)束時間戳)的前 N 筆交易信息。這個 Frame 適用于用戶想要了解特定賬戶在一定時間窗口內(nèi)的交易活動。
- 「Frame 3」 :Frame 3 接受證券符號、開始時間戳、結(jié)束時間戳以及交易數(shù)量(N)作為輸入。它會返回在指定時間范圍內(nèi)(包括開始和結(jié)束時間戳)的前 N 筆特定證券的交易信息。這個 Frame 用于分析特定證券的市場表現(xiàn)和交易活動。
- 「Frame 4」 :Frame 4 接受客戶賬戶 ID 和一個時間戳作為輸入。它會識別出在指定時間戳或之后該客戶賬戶的第一筆交易,并返回最多 20 條與這筆交易 ID 相關(guān)的持倉歷史變更記錄。這些歷史變更記錄包括由這筆交易對之前交易創(chuàng)建的持倉所做的更改,以及后續(xù)交易對由此交易創(chuàng)建的任何持倉所做的更改。
部分 sql:
-- 3.3.6 Trade-Lookup
Query SET TRANSACTION ISOLATION LEVEL READ COMMITTED
-- F1
Execute SELECT t_bid_price, t_exec_name, t_is_cash, tt_is_mrkt, t_trade_price FROM trade, trade_type WHERE t_id = '200000005238470' AND t_tt_id = tt_id
Execute SELECT se_amt, DATE_FORMAT(se_cash_due_date, '%Y-%m-%d'), se_cash_type FROM settlement WHERE se_t_id = '200000005238470'
Execute SELECT ct_amt, DATE_FORMAT(ct_dts, '%Y-%m-%d %H:%i:%s.%f'), ct_name FROM cash_transaction WHERE ct_t_id = '200000005238470'
Execute SELECT DATE_FORMAT(th_dts, '%Y-%m-%d %H:%i:%s.%f'), th_st_id FROM trade_history WHERE th_t_id = '200000005238470' ORDER BY th_dts LIMIT 3
-- F2
Query SELECT t_bid_price, t_exec_name, t_is_cash, tt_is_mrkt, t_trade_price FROM trade, trade_type WHERE t_id = 200000005236617 AND t_tt_id = tt_id
Query SELECT se_amt, DATE_FORMAT(se_cash_due_date, '%Y-%m-%d'), se_cash_type FROM settlement WHERE se_t_id = 200000005236617
Query SELECT ct_amt, DATE_FORMAT(ct_dts, '%Y-%m-%d %H:%i:%s.%f'), ct_name FROM cash_transaction WHERE ct_t_id = 200000005236617
Query SELECT DATE_FORMAT(th_dts, '%Y-%m-%d %H:%i:%s.%f'), th_st_id FROM trade_history WHERE th_t_id = 200000005236617 ORDER BY th_dts LIMIT 3
Query COMMIT
-- F3
-- F4
Trade-Order
?
代碼中,第 5、6 步是 rollback或 commit,其余四個步驟請參考
TOF1_1 ~ TOF4_2
?
Trade-Order 事務(wù)由 EGenDriverCE 執(zhí)行,它包含「六個 Frame」,是非常巨大的事務(wù)。這個事務(wù)模擬了客戶、經(jīng)紀(jì)人或授權(quán)第三方買賣證券的過程,包括驗證交易執(zhí)行者的授權(quán)、估算交易的財務(wù)影響以及提交或取消交易。
- 「獲取客戶信息」:事務(wù)首先使用傳入的賬戶 ID 獲取客戶、客戶賬戶和賬戶經(jīng)紀(jì)人的信息。這是為了確保后續(xù)操作能夠在正確的賬戶上下文中進(jìn)行。
- 「驗證執(zhí)行者」:接下來,事務(wù)會驗證執(zhí)行交易的人是否具有適當(dāng)?shù)氖跈?quán)。如果執(zhí)行者未獲授權(quán),事務(wù)將回滾。在基準(zhǔn)測試執(zhí)行期間,CE 總是生成授權(quán)的執(zhí)行者。
- 「估算交易影響」:事務(wù)的下一步是估算執(zhí)行交易的總體財務(wù)影響。對于限價單,使用請求的價格進(jìn)行估算;對于市價單,使用當(dāng)前市場價值。估算過程包括評估交易對現(xiàn)有持倉的影響,計算可能實現(xiàn)的利潤的資本收益稅,以及計算行政費用和經(jīng)紀(jì)人傭金。如果是保證金交易,還會評估客戶賬戶的總資產(chǎn)。
- 「記錄訂單」:使用上述信息記錄訂單。這一步驟確保了交易的詳細(xì)信息被正確地保存在系統(tǒng)中,以便后續(xù)處理。
- 「提交或回滾」:在完成所有處理后,事務(wù)會根據(jù)一定的比例選擇提交或回滾。這模擬了實際交易中可能出現(xiàn)的取消訂單或錯誤條件。所有其他事務(wù)則被提交。
- 「發(fā)送交易到 MEE」:對于成功提交的市價訂單,EGenTxnHarness 會將交易發(fā)送到適當(dāng)?shù)?MEE。這是模擬交易流程的最后一步,確保交易能夠被市場交易所處理。
Trade-Result
Trade-Result 事務(wù)由 EGenDriverMEE 執(zhí)行,它包含「六個 Frame」。這個事務(wù)模擬了完成股票市場交易的過程,即經(jīng)紀(jì)行從市場交易所接收到交易的最終確認(rèn)和價格。客戶的持倉將根據(jù)交易的完成情況進(jìn)行更新,同時生成的估計數(shù)據(jù)(如經(jīng)紀(jì)人傭金等)將被實際數(shù)值替換,并記錄交易的歷史信息以供后續(xù)參考。
- 「獲取交易信息」:事務(wù)的第一步是使用傳入的交易 ID 獲取交易的相關(guān)信息。這包括客戶的賬戶 ID,用于進(jìn)一步查詢賬戶信息。
- 「更新客戶持倉」:接下來,根據(jù)交易的類型(買入或賣出)、涉及的股票數(shù)量以及客戶當(dāng)前的持倉情況(多頭或空頭),更新客戶的持倉。這可能涉及清算現(xiàn)有持倉以覆蓋銷售,或者在購買股票時使用現(xiàn)有空頭持倉。
- 「計算稅款」:如果交易實現(xiàn)利潤且利潤需要繳稅,將計算應(yīng)繳稅款。
- 「計算經(jīng)紀(jì)人傭金」:計算經(jīng)紀(jì)人的傭金,并將所有與交易相關(guān)的信息記錄下來。
- 「提交交易記錄」:最后,為交易創(chuàng)建結(jié)算記錄,并在交易不是保證金交易的情況下更新客戶的賬戶余額。
這個事務(wù)的設(shè)計確保了交易完成后所有必要的更新和記錄都能被正確處理,反映了實際金融系統(tǒng)中交易結(jié)算的復(fù)雜性。在基準(zhǔn)測試中,它有助于評估系統(tǒng)在處理交易結(jié)果時的性能和準(zhǔn)確性。
下面 sql 是一個例子,但這個例子只走了一部分分支,例如 F2、F3 有一些就沒有走到。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
-- F1
SELECT t_ca_id, t_tt_id, t_s_symb, t_qty, t_chrg, t_lifo, t_is_cash FROM trade WHERE t_id = 200000014584794
SELECT tt_name, tt_is_sell, tt_is_mrkt FROM trade_type WHERE tt_id = _latin1'TMS'
SELECT hs_qty FROM holding_summary WHERE hs_ca_id = 43000012441 AND hs_s_symb = _latin1'BDGPRB'
-- F2
SELECT ca_b_id, ca_c_id, ca_tax_st FROM customer_account WHERE ca_id = 43000012441
-- TRF2_2a INSERT, or TRF2_2b UPDATE
UPDATE holding_summary SET hs_qty = 8700 WHERE hs_ca_id = 43000012441 AND hs_s_symb = _latin1'BDGPRB'
-- MEESUT_STMT_TRF2_3a ASC, or TRF2_3b DESC
SELECT h_t_id, h_qty, h_price FROM holding WHERE h_ca_id = '43000012441' AND h_s_symb = 'BDGPRB' ORDER BY h_dts ASC
-- TRF2_4
INSERT INTO holding_history(hh_h_t_id, hh_t_id, hh_before_qty, hh_after_qty) VALUES('200000013784914', '200000014584794', '700', '600')
-- TRF2_5a or TRF2_5b (DELETE)
UPDATE holding SET h_qty = '600' WHERE h_t_id = '200000013784914'
-- TRF3_1 在這個事務(wù)中 miss,如果要尋找,其他事務(wù)中可以搜到
-- SELECT sum(tx_rate) FROM taxrate, customer_taxrate WHERE tx_id = cx_tx_id AND cx_c_id = ?
-- TRF4_1
SELECT s_ex_id, s_name FROM security WHERE s_symb = _latin1'BDGPRB'
-- TRF4_2
SELECT c_tier FROM customer WHERE c_id = 4300001245
-- TRF4_3
SELECT cr_rate FROM commission_rate WHERE cr_c_tier = 1 AND cr_tt_id = _latin1'TMS' AND cr_ex_id = _latin1'NASDAQ' AND cr_from_qty <= 100 AND cr_to_qty >= 100
-- TRF5_1
UPDATE trade SET t_comm = 1.14299999999999997e+01, t_dts = _latin1'2024-02-27 20:48:15.000000', t_st_id = _latin1'CMPT', t_trade_price = 2.85799999999999983e+01 WHERE t_id = 200000014584794
-- TRF5_2
INSERT INTO trade_history(th_t_id, th_dts, th_st_id) VALUES(200000014584794, _latin1'2024-02-27 20:48:15.000000', _latin1'CMPT')
-- TRF5_3
UPDATE broker SET b_comm_total = b_comm_total + 1.14299999999999997e+01, b_num_trades = b_num_trades + 1 WHERE b_id = 4300000017
-- TRF6_1
INSERT INTO settlement(se_t_id, se_cash_type, se_cash_due_date, se_amt) VALUES(200000014584794, _latin1'Cash Account', _latin1'2024-02-29', 2.84157000000000016e+03)
-- TRF6_2
UPDATE customer_account SET ca_bal = ca_bal + 2.84157000000000016e+03 WHERE ca_id = 43000012441
-- TRF6_3
INSERT INTO cash_transaction(ct_dts, ct_t_id, ct_amt, ct_name) VALUES(_latin1'2024-02-27 20:48:15.000000', 200000014584794, 2.84157000000000016e+03, _latin1'Market-Sell 100 shared of PREF_B of Bandag, Inc.')
-- TRF6_4
SELECT ca_bal FROM customer_account WHERE ca_id = 43000012441
COMMIT
Trade-Status
Trade-Status 事務(wù)由 EGenDriverCE 執(zhí)行,它包含一個 Frame。這個事務(wù)模擬了客戶查看其賬戶最近交易活動摘要的過程,通常是為了回顧最近的交易記錄。
- 「Frame 1」:這個 Frame 負(fù)責(zé)檢索給定賬戶 ID 的最近 50 筆交易的狀態(tài)信息。這包括交易 ID、交易時間、狀態(tài)名稱、交易類型名稱、證券符號、交易數(shù)量、執(zhí)行交易的人員名稱、交易費用、證券名稱以及交易所名稱。
-- 設(shè)置事務(wù)隔離級別為 READ COMMITTED,確保事務(wù)在讀取數(shù)據(jù)時的一致性
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 執(zhí)行查詢,獲取最近 50 筆交易的狀態(tài)信息
SELECT
t_id, DATE_FORMAT(t_dts,'%Y-%m-%d %H:%i:%s.%f'), st_name, tt_name, t_s_symb, t_qty, t_exec_name, t_chrg, s_name, ex_name
FROM
trade, status_type, trade_type, security, exchange
WHERE
t_ca_id = '43000003162' -- 指定客戶賬戶 ID
AND st_id = t_st_id -- 確保交易狀態(tài)與交易 ID 匹配
AND tt_id = t_tt_id -- 確保交易類型與交易 ID 匹配
AND s_symb = t_s_symb -- 確保證券符號與交易 ID 匹配
AND ex_id = s_ex_id -- 確保交易所與證券符號匹配
ORDER BY
t_dts DESC -- 按交易時間降序排列
LIMIT 50; -- 限制結(jié)果為最近的 50 筆交易
-- 關(guān)閉語句
Close stmt;
-- 執(zhí)行查詢,獲取客戶、賬戶和經(jīng)紀(jì)人的詳細(xì)信息
SELECT
c_l_name, c_f_name, b_name
FROM
customer_account, customer, broker
WHERE
ca_id = '43000003162' -- 指定客戶賬戶 ID
AND c_id = ca_c_id -- 確保客戶賬戶與客戶 ID 匹配
AND b_id = ca_b_id; -- 確保經(jīng)紀(jì)人 ID 與客戶賬戶匹配
-- 關(guān)閉語句
Close stmt;
-- 提交事務(wù),確保所有查詢結(jié)果被正確處理
Query COMMIT;
在這個事務(wù)中,首先設(shè)置了事務(wù)的隔離級別,然后執(zhí)行了兩個查詢。第一個查詢用于獲取交易狀態(tài)信息,第二個查詢用于獲取與交易相關(guān)的客戶、賬戶和經(jīng)紀(jì)人的詳細(xì)信息。
Trade-Update
Trade-Update 事務(wù)由 EGenDriverCE 執(zhí)行,它包含「三個互斥的 Frame」。每個 Frame 使用不同的技術(shù)來查找和更新歷史交易數(shù)據(jù)。
「Frame 1」
- 接受一組交易 ID 的列表。
- 返回列表中每個交易的信息。
- 對于每個交易,修改執(zhí)行者的名稱。
-- 查詢特定交易 ID 的執(zhí)行者名字
SELECT t_exec_name FROM trade WHERE t_id = '200000001949399';
-- 更新執(zhí)行者名字
UPDATE trade SET t_exec_name = 'Jessica X Lowery' WHERE t_id = '200000001949399';
-- 查詢交易相關(guān)信息
SELECT t_bid_price, t_exec_name, t_is_cash, tt_is_mrkt, t_trade_price FROM trade, trade_type WHERE t_id = '200000001949399' AND t_tt_id = tt_id;
-- 查詢結(jié)算信息
SELECT se_amt, DATE_FORMAT(se_cash_due_date, '%Y-%m-%d'), se_cash_type FROM settlement WHERE se_t_id = '200000001949399';
-- 查詢現(xiàn)金交易信息
SELECT ct_amt, DATE_FORMAT(ct_dts, '%Y-%m-%d %H:%i:%s.%f'), ct_name FROM cash_transaction WHERE ct_t_id = '200000001949399';
-- 查詢交易歷史記錄
SELECT DATE_FORMAT(th_dts, '%Y-%m-%d %H:%i:%s.%f'), th_st_id FROM trade_history WHERE th_t_id = '200000001949399' ORDER BY th_dts LIMIT 3;
-- 查詢另一個交易 ID 的執(zhí)行者名字
SELECT t_exec_name FROM trade WHERE t_id = 200000000135883;
-- 更新執(zhí)行者名字
UPDATE trade SET t_exec_name = _latin1'Roxann Kniffen' WHERE t_id = 200000000135883;
-- 提交事務(wù)
COMMIT;
「Frame 2」
- 接受客戶賬戶 ID、開始時間戳、結(jié)束時間戳和交易數(shù)量(N)作為輸入。
- 返回指定客戶賬戶在指定時間范圍內(nèi)的前 N 筆交易信息。
- 修改每筆交易的結(jié)算現(xiàn)金類型。
-- 設(shè)置事務(wù)隔離級別為可重復(fù)讀
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 查詢特定客戶賬戶 ID 在指定時間范圍內(nèi)的交易信息
SELECT t_bid_price, t_exec_name, t_is_cash, t_id, t_trade_price FROM trade WHERE t_ca_id = 43000008818 AND t_dts >= _latin1'2005-01-27 13:24:52.109000' AND t_dts <= _latin1'2005-03-14 09:15:00.000000' ORDER BY t_dts ASC LIMIT 20;
-- 對于每筆交易,更新結(jié)算類型為 'Cash'
-- 下面的語句會重復(fù)多組
SELECT se_cash_type FROM settlement WHERE se_t_id = 200000002704863;
UPDATE settlement SET se_cash_type = 'Cash' WHERE se_t_id = 200000002704863;
-- 查詢并返回與特定交易 ID 相關(guān)的結(jié)算信息
SELECT se_amt, DATE_FORMAT(se_cash_due_date, '%Y-%m-%d'), se_cash_type FROM settlement WHERE se_t_id = 200000002704863;
-- 查詢并返回與特定交易 ID 相關(guān)的現(xiàn)金交易信息
SELECT ct_amt, DATE_FORMAT(ct_dts, '%Y-%m-%d %H:%i:%s.%f'), ct_name FROM cash_transaction WHERE ct_t_id = 200000002704863;
-- 查詢并返回與特定交易 ID 相關(guān)的交易歷史記錄
SELECT DATE_FORMAT(th_dts, '%Y-%m-%d %H:%i:%s.%f'), th_st_id FROM trade_history WHERE th_t_id = 200000002704863 ORDER BY th_dts LIMIT 3;
-- 提交事務(wù)
Query COMMIT;
「Frame 3」
- 接受證券符號、開始時間戳、結(jié)束時間戳和交易數(shù)量(N)作為輸入。
- 返回給定證券在指定時間范圍內(nèi)的前 N 筆交易信息。
- 對于現(xiàn)金交易,修改交易描述。
-- 查詢特定證券符號在指定時間范圍內(nèi)的交易信息
SELECT t_ca_id, t_exec_name, t_is_cash, t_trade_price, t_qty, s_name, DATE_FORMAT(t_dts, '%Y-%m-%d %H:%i:%s.%f'), t_id, t_tt_id, tt_name FROM trade, trade_type FORCE INDEX(PRIMARY), security WHERE t_s_symb = _latin1'AMGN' AND t_dts >= _latin1'2005-02-09 16:05:31.891000' AND t_dts <= _latin1'2005-03-14 09:15:00.000000' AND tt_id = t_tt_id AND s_symb = t_symb ORDER BY t_dts ASC LIMIT 20;
-- 對于每筆現(xiàn)金交易,更新交易描述
-- 下面的語句會重復(fù)多組
SELECT se_amt, DATE_FORMAT(se_cash_due_date, '%Y-%m-%d'), se_cash_type FROM settlement WHERE se_t_id = 200000004055564;
SELECT ct_name FROM cash_transaction WHERE ct_t_id = 200000004055564;
UPDATE cash_transaction SET ct_name = _latin1'Limit-Sell 400 Shares of COMMON of Amgen, Inc.' WHERE ct_t_id = 200000004055564;
-- 查詢并返回與特定交易 ID 相關(guān)的結(jié)算信息
SELECT ct_amt, DATE_FORMAT(ct_dts, '%Y-%m-%d %H:%i:%s.%f'), ct_name FROM cash_transaction WHERE ct_t_id = 200000004055564;
-- 查詢并返回與特定交易 ID 相關(guān)的交易歷史記錄
SELECT DATE_FORMAT(th_dts, '%Y-%m-%d %H:%i:%s.%f'), th_st_id FROM trade_history WHERE th_t_id = 200000004055564 ORDER BY th_dts ASC LIMIT 3;
Data-Maintenance
Data-Maintenance 只有一個 frame,但是這個 frame 非常復(fù)雜。可能是由于 time triggered,因此 tpce_50k_sorted_id_time.csv 中并未出現(xiàn)。Data-Maintenance 事務(wù)由 EGenDriverDM 執(zhí)行,它包含一個 Frame。這個事務(wù)模擬了對數(shù)據(jù)庫中主要用作參考的靜態(tài)數(shù)據(jù)進(jìn)行定期修改的過程。
「Frame 1」
- 這個 Frame 負(fù)責(zé)執(zhí)行數(shù)據(jù)維護(hù)操作,這些操作包括更新賬戶權(quán)限、地址信息、公司信用評級、客戶電子郵件地址、客戶稅率、市場數(shù)據(jù)、交易所描述、財務(wù)數(shù)據(jù)、新聞項、證券交易日期、稅率以及觀察列表中的證券符號。
- 每次運行這個事務(wù)時,EGenTxnHarness 會提供要修改的表的名稱作為輸入。
- 事務(wù)會根據(jù)提供的表名選擇下一個要修改的表,這意味著每個表大約每十二分鐘只會被修改一次。
- 對于每個表,事務(wù)會執(zhí)行特定的更新操作,例如更改信用評級、電子郵件地址、稅率等,以保持?jǐn)?shù)據(jù)的時效性和準(zhǔn)確性。
Trade-Cleanup
Trade-Cleanup 事務(wù)由 EGenDriverDM 執(zhí)行,它包含一個 Frame。這個事務(wù)的目的是清理數(shù)據(jù)庫中的掛起或已提交的交易,以便在測試運行之前將數(shù)據(jù)庫恢復(fù)到已知狀態(tài)。
僅在測試開始時執(zhí)行一次。
「Frame 1」
- 設(shè)置事務(wù)隔離級別為 READ COMMITTED,確保事務(wù)在讀取數(shù)據(jù)時的一致性。
- 查詢
trade_request
表,獲取所有待處理交易的交易 ID。 - 對于每個待處理的交易,執(zhí)行以下步驟:
- 在
trade_history
表中插入一條新記錄,表示交易已被提交(SBMT
表示提交)。 - 更新
trade
表,將交易狀態(tài)設(shè)置為已取消(CNCL
),并記錄當(dāng)前的日期和時間。 - 再次在
trade_history
表中插入一條新記錄,記錄交易的取消狀態(tài)。
這個過程確保了所有未完成的交易都被正確地標(biāo)記和記錄,以便在測試運行開始時數(shù)據(jù)庫處于一個干凈的狀態(tài)。
-- 設(shè)置事務(wù)隔離級別為 READ COMMITTED
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 選擇 trade_request 表中的所有交易 ID 并排序
SELECT tr_t_id FROM trade_request ORDER BY tr_t_id;
-- 為每個交易 ID 插入一條記錄到 trade_history 表,表示交易已提交
INSERT INTO trade_history (th_t_id, th_dts, th_st_id) VALUES ('200000014582105', '2024-02-27 20:48:13', 'SBMT');
-- 重復(fù)多次,為每個交易 ID 更新 trade 表,設(shè)置狀態(tài)為已取消,并記錄時間
UPDATE trade SET t_st_id = 'CNCL', t_dts = '2024-02-27 20:48:13' WHERE t_id = '200000014582105';
-- 為已取消的交易插入一條記錄到 trade_history 表
INSERT INTO trade_history (th_t_id, th_dts, th_st_id) VALUES (200000014582105, _latin1'2024-02-27 20:48:13', _latin1'CNCL');
-- 如果有其他交易 ID,也執(zhí)行相同的插入和更新操作
-- 例如:
INSERT INTO trade_history (th_t_id, th_dts, th_st_id) VALUES (200000014582119, _latin1'2024-02-27 20:48:13', _latin1'SBMT');
輕松上手:TPCE for MySQL
TPCE 起初只有面向PostgreSQL 的版本,Percona 公司貢獻(xiàn)了針對 MySQL的版本:https://github.com/Percona-Lab/tpce-mysql。
這個版本仍然存在編譯問題,建議通過下面的改版來安裝 tpce-mysql:https://github.com/VincentS/tpcemysql
下面是 Debian 系統(tǒng)的安裝過程。首先安裝 tpcemysql 的依賴項:
# 安裝 unixodbc
sudo apt-get install unixodbc unixodbc-dev
# 安裝 mysql8 的驅(qū)動:
wget https://downloads.mysql.com/archives/get/p/10/file/mysql-connector-odbc_8.0.20-1debian9_amd64.deb
sudo dpkg -i mysql-connector-odbc_8.0.20-1debian9_amd64.deb
sudo apt-get install -f
tpcemysql 需要通過 odbc 連接 mysql,因此配置 odbc :
# 設(shè)置 odbc 環(huán)境變量 /etc/odbcinst.ini
# 若[MySQL ODBC 8.0 Driver]已經(jīng)存在,則需要先刪除,避免重復(fù)
cat /etc/odbcinst.ini
[MySQL ODBC 8.0 Driver]
Description=MySQL ODBC 8.0 Driver
Driver=/usr/lib/x86_64-linux-gnu/odbc/libmyodbc8w.so
Setup=/usr/lib/x86_64-linux-gnu/odbc/libmyodbc8w.so
# 設(shè)置 odbc 連接信息
cat /etc/odbc.ini
[MySQLServer_ODBC_NAME]
Description=My MySQL tpce
Driver=MySQL ODBC 8.0 Driver
Server=xxx.xxx.xxx.xxx
Port=3308
User=root
Password=password
Database=tpce
Option=3
接下來編譯 tpce-mysql:
git clone git@github.com:VincentS/tpcemysql.git
cd tpce_mysql
mkdir flat_out
cd prj
make clean
# 修改 makefile
# 將 CCFLAGS=-g -O2 -Wall -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DHANA_ODBC -DUSE_PREPARE 中的 -DHANA_ODBC 修改為 -DMYSQL_ODBC
cp Makefile.Mysql Makefile
make
生成 + 導(dǎo)入 tpce 數(shù)據(jù)。
cd ~/tpcemysql
# 生成數(shù)據(jù),生成后,數(shù)據(jù)會寫入 flat_out,等待 LOAD DATA INFILE
./bin/EGenLoader -i flat_in -o flat_out -c 2000 -t 2000 -f 200 -w 50
cd scripts/mysql/
# 首先在 mysql 中創(chuàng)建一個空庫 tpce
# 步驟 1:建表
mysql --local-infile=1 -h 127.0.0.1 -uroot -ppassword -P 3308 -Dtpce < 1_create_table.sql
# 導(dǎo)入數(shù)據(jù)等等后續(xù)操作與步驟 1 類似
mysql --local-infile=1 -h 127.0.0.1 -uroot -ppassword -P 3308 -Dtpce < 2_load_data.sql
mysql --local-infile=1 -h 127.0.0.1 -uroot -ppassword -P 3308 -Dtpce < 3_create_index.sql
mysql --local-infile=1 -h 127.0.0.1 -uroot -ppassword -P 3308 -Dtpce < 4_create_fk.sql
mysql --local-infile=1 -h 127.0.0.1 -uroot -ppassword -P 3308 -Dtpce < 5_create_sequence.sql
運行:
cd ~/tpcemysql
./bin/EGenSimpleTest -c 2000 -a 2000 -f 200 -d 50 -l 200 -e flat_in -j tpce -U root -P password -r 10 -u 10 -t 90 -D MySQLServer_ODBC_NAME
實踐挑戰(zhàn):給 TPCE 推薦索引
為 MySQL 推薦索引是很常見的優(yōu)化手段。對于 OLAP 或 OLTP 業(yè)務(wù)場景都有重要意義。其中,OLAP 業(yè)務(wù)的難點在于對復(fù)雜 join 關(guān)系、復(fù)雜操作子(子函數(shù)、GROUP BY、單值或范圍查詢)的理解,而 OLTP 業(yè)務(wù)的難點在于【慢 SQL + 基礎(chǔ) SQL】的綜合理解。
TPCC 和 TPCE benchmark 自身提供了較為合理的普通索引、唯一鍵索引(UK)和外鍵索引(FK),我們將 benchmark 標(biāo)準(zhǔn)索引組合成為 GT(Ground Truth),這是索引推薦算法致力于達(dá)到的目標(biāo)。我們對比了流行的友商開源算法Soar和字節(jié)跳動自研算法的SQLBrain的推薦效果。
下面的測試結(jié)果展現(xiàn)了 TPC-E 的意義:「TPC-E 顯然是難度更大、挑戰(zhàn)性更高的基準(zhǔn)測試?!?/strong> 由于 TPC-C 過于簡單,Soar 和 SQLBrain 算法都可以達(dá)到不錯的效果(超過 GT 性能的 95%),「測試不出差距」。但是 TPC-E 上兩種方法拉開了差距。Soar 推薦的索引僅能達(dá)到 14.4 tpsE(GT 性能的16% 左右),而 SQLBrain 仍可以達(dá)到 GT 性能的 95% 以上。
為字節(jié)跳動ByteBrain團(tuán)隊自研的MySQL索引推薦系統(tǒng) 「SQLBrain」 打個廣告:「SQLBrain」 在 TPC-E 的推薦效果達(dá)到 Ground Truth 的「98%」(對比流行的開源工具 Soar 推薦效果僅達(dá)到 「16%」),已經(jīng)在字節(jié)跳動的業(yè)務(wù)中接入了近x萬個MySQL實例,覆蓋電商、財經(jīng)、國際支付、直播、廣告等多種業(yè)務(wù)。相關(guān)技術(shù)正在準(zhǔn)備開源,敬請期待。??
總結(jié)
TPC-E 可以被視為 TPC-C 的強化升級版,引入了更復(fù)雜的事務(wù)、更復(fù)雜的關(guān)系表和執(zhí)行邏輯,增大了 OLTP Benchmark 的挑戰(zhàn)性。在 TPC-C 過于簡單、已經(jīng)被充分優(yōu)化的今天,TPC-E 作為 一種更復(fù)雜的 OLTP Benchmark,可以在索引推薦、性能調(diào)參等領(lǐng)域展現(xiàn)作用、挖掘各種算法技術(shù)的能力瓶頸。
參考文獻(xiàn)
- TPC-E 官網(wǎng): https://www.tpc.org/tpce/
- TPC-E pdf 規(guī)范:https://www.tpc.org/TPC_Documents_Current_Versions/pdf/TPC-E_v1.14.0.pdf
- Chen, Shimin, et al. "TPC-E vs. TPC-C: Characterizing the new TPC-E benchmark via an I/O comparison study." ACM Sigmod Record 39.3 (2011): 5-10.
- T?zün, P?nar, et al. "From A to E: analyzing TPC's OLTP benchmarks: the obsolete, the ubiquitous, the unexplored." EDBT. 2013.