架构
下面描述的 sqlite 数据库当前为 52 GB。它是作为 Entity Framework Core 6.0 项目的一部分生成的。
Trades
桌子_
CREATE TABLE IF NOT EXISTS "Trades" (
"Id" INTEGER NOT NULL CONSTRAINT "PK_Trades" PRIMARY KEY AUTOINCREMENT,
"SymbolId" INTEGER NOT NULL,
"Price" TEXT NOT NULL,
"Quantity" TEXT NOT NULL,
"TimeStamp" TEXT NOT NULL,
"Side" INTEGER NOT NULL,
"Type" INTEGER NOT NULL,
CONSTRAINT "FK_Trades_Symbols_SymbolId" FOREIGN KEY ("SymbolId") REFERENCES "Symbols" ("Id") ON DELETE CASCADE
);
这包含来自 Kraken 加密货币交易所的交易。
数据是从此处下载的 CSV 填充的:
最近的交易是通过 API 检索的。
数据摘录:
sqlite> SELECT * FROM Trades LIMIT 5;
Id SymbolId Price Quantity TimeStamp Side Type
-------- -------- ----- --------- ------------------- ---- ----
17272735 29 2.364 29.18557 2021-08-10 15:31:26 0 0
17272736 29 2.364 12.50281 2021-08-10 15:31:34 0 0
17272737 29 2.363 416.76043 2021-08-10 15:31:36 0 0
17272738 29 2.365 38.94156 2021-08-10 15:32:00 0 0
17272739 29 2.363 0.41676 2021-08-10 15:32:05 0 0
表的当前大小:
sqlite> SELECT COUNT(*) FROM Trades;
COUNT(*)
---------
535560814
Run Time: real 7.746 user 0.984375 sys 6.750000
Symbols
桌子_
CREATE TABLE IF NOT EXISTS "Symbols" (
"Id" INTEGER NOT NULL CONSTRAINT "PK_Symbols" PRIMARY KEY AUTOINCREMENT,
"Name" TEXT NOT NULL
);
每个交易对都有一个符号。例如XBTUSD
比特币。
数据摘录:
sqlite> SELECT * FROM Symbols LIMIT 5;
Id Name
-- --------
29 1INCHEUR
30 1INCHUSD
31 AAVEAUD
32 AAVEETH
33 AAVEEUR
一些关键指标
一些关键列的索引:
CREATE UNIQUE INDEX "IX_Symbols_Name" ON "Symbols" ("Name");
CREATE INDEX "IX_Trades_SymbolId" ON "Trades" ("SymbolId");
CREATE INDEX "IX_Trades_TimeStamp" ON "Trades" ("TimeStamp");
查询性能
到目前为止,我运行的大多数基本查询似乎都很慢。这里有些例子。
最近 10 笔 XBTUSD 交易(31 秒)
SELECT *
FROM Trades
WHERE SymbolId = (SELECT Id FROM Symbols WHERE Name = 'XBTUSD')
ORDER BY TimeStamp DESC
LIMIT 10;
Run Time: real 31.641 user 28.984375 sys 2.640625
Id SymbolId Price Quantity TimeStamp Side Type
--------- -------- ------- ---------- ----------------------- ---- ----
552833548 377 48683.1 0.157 2021-12-06 06:16:17.804 1 0
552833547 377 48681.5 0.00049872 2021-12-06 06:16:04.855 0 0
552833546 377 48681.4 0.32 2021-12-06 06:16:02.729 1 0
552833545 377 48680.4 0.1 2021-12-06 06:15:53.826 0 0
552833544 377 48697.4 0.05 2021-12-06 06:15:39.56 1 1
552833543 377 48694.5 0.04923492 2021-12-06 06:15:22.787 0 0
552833542 377 48690.2 0.00210422 2021-12-06 06:15:22.786 0 0
552833541 377 48689.6 0.02201001 2021-12-06 06:15:22.487 0 0
552833540 377 48682.5 0.00052279 2021-12-06 06:15:22.486 0 0
552833539 377 48652.3 0.00011573 2021-12-06 06:15:22.485 0 0
按月显示 XBTUSD 的最高价和最低价(64 秒)
SELECT
strftime('%Y-%m', TimeStamp) AS date,
COUNT(*) AS trade_count,
min( CAST(Price AS DECIMAL) ) AS high,
max( CAST(Price AS DECIMAL) ) AS low
FROM Trades
WHERE
SymbolId = (SELECT Id FROM Symbols WHERE Name = 'XBTUSD')
GROUP BY strftime('%Y-%m', TimeStamp)
ORDER BY date;
Run Time: real 64.743 user 55.421875 sys 8.625000
date trade_count high low
------- ----------- --------- ---------
2013-10 422 122 207.30246
2013-11 7147 201.04 1198.8009
2013-12 14964 380 1130
2014-01 7747 737.15115 1019
2014-02 8990 450 835
2014-03 4314 436.07375 720
2014-04 3063 353.75804 583.75327
2014-05 2046 422.19 629.0355
2014-06 2533 525 677.90898
2014-07 838 566.75121 658.87046
2014-08 1756 455 602.36146
2014-09 930 295 527.99987
2014-10 1188 273.32564 418.98998
...
按交易品种分类的交易数量(53 秒)
SELECT Symbols.Name, SymbolId, COUNT(*) AS trade_count
FROM Trades JOIN Symbols ON Trades.SymbolId = Symbols.Id
GROUP BY SymbolId
ORDER BY trade_count;
Run Time: real 53.176 user 46.031250 sys 7.031250
Name SymbolId trade_count
--------- -------- -----------
WBTCXBT 369 561
RAYUSD 291 674
WBTCUSD 368 1003
YFIAUD 407 1460
GHSTGBP 167 1488
WBTCEUR 367 1860
FILAUD 154 2036
RAYEUR 290 2154
BNTGBP 88 2437
GRTAUD 174 2514
ZRXGBP 417 2732
BNTXBT 90 3196
SUSHIGBP 333 3387
...
问题
您对如何提高上述查询的性能有什么建议吗?
即你会推荐额外的指数吗?或者也许我应该看看一些特定于 sqlite 的参数?
或者你会说,基于数据库的大小和它是 sqlite 的事实,这样的查询只会很慢。如果是这样的话,我想我可以考虑使用 SQL Server 或 Postgresql。我喜欢 sqlite 的想法,因为就设置而言,它的开销最低。它也是免费的(与 SQL Server 不同)。
笔记
尽管我在上面展示了 sqlite 查询,但数据库和架构是通过 Entity Framework Core 6.0 项目创建的。
包含 EF Core 数据库代码以及从 CSV 和 API 导入贸易数据的程序的项目可在此处获得:
https://github.com/dharmatech/kraken-trades-database
实体模型和数据库上下文:
导入 CSV 的代码(如果您好奇的话):
https://github.com/dharmatech/kraken-trades-database/blob/008-import-api/KrakenImportCsv/Program.cs
通过 API 导入的代码(如果您好奇的话):
https://github.com/dharmatech/kraken-trades-database/blob/008-import-api/KrakenImportApi/Program.cs
文本列
Lasse 在下面的评论中提出了一个很好的问题:
您的价格和金额输入文本而不是 REAL 是否有原因
他指的是表中的这些列Trades
:
"Price" TEXT NOT NULL,
"Quantity" TEXT NOT NULL,
这就是 EF Core 从以下 C# 模型类生成的内容:
[Index(nameof(TimeStamp))]
public class Trade
{
public int Id { get; set; }
public int SymbolId { get; set; }
public Symbol Symbol { get; set; } // navigation property
public decimal Price { get; set; }
public decimal Quantity { get; set; }
public DateTime TimeStamp { get; set; }
public OrderSide Side { get; set; }
public OrderTypeMinimal Type { get; set; }
}