3

架构

下面描述的 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 填充的:

https://support.kraken.com/hc/en-us/articles/360047543791-Downloadable-historical-market-data-time-and-sales

最近的交易是通过 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

实体模型和数据库上下文:

https://github.com/dharmatech/kraken-trades-database/blob/008-import-api/KrakenTradesDatabase/Model.cs

导入 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; }
}
4

0 回答 0