背景
我正在尝试设计一个PostgreSQL数据库,该数据库将存储来自加密货币交易所的交易记录。我的客户中只有一个Trade
模型,但想根据交易代表的符号将交易分为各自的表格。可用的符号在运行时推导,并且从交易所进行的交易每个都有自己的ID序列(从0开始)。
例如,说我想从Binance缓存交易。我的客户会调用他们的API,看到平台上可用的(一些)符号为BTCUSDT
,ETHUSDT
和ETHBTC
,并且如果这些符号不在{ {1}}表,它将插入它们,并创建一个新表bn.Symbols
。
我正在使用的技术堆栈是带有Dapper和PostgreSQL的.NET Core 3。
问题
我看过几篇文章,详细介绍了如何编写以提供的变量作为名称以及a common sentiment seems to be that this is a poor design来创建表的过程或函数。
除了这种负面情绪外,我的客户还使用存储库和工作单元模式,并且bn.Trades-SYMBOLNAME
的接口方式定义了TradeRepository
方法,因此我无法指定哪个符号我想以存储库为目标,也不能在不使用一些肮脏技巧的情况下在存储库功能中指定符号。
一个简单的解决方案是将所有交易存储在同一张表中,为GetById(long)
创建一个外键列,并为Symbol
和Id
列创建一个唯一的复合索引。但是,我很犹豫,因为我最终将存储超过10亿笔交易,而且这种方法仍然会给我当前的存储库模式设计带来问题。
有没有更好的方法来解决这个问题?
代码
以下代码显示了我的模型当前的配置方式:
Symbol
以下是所有存储库的接口方式:
public abstract class EntityBase : IEntity
{
#region Properties
public long Id
{
get;
set;
}
#endregion
}
public class Symbol : EntityBase
{
#region Data Members
private long _baseAssetId;
private long _quoteAssetId;
#endregion
#region Properties
public string Name
{
get;
set;
}
public long BaseAssetId
{
get
{
if( BaseAsset != null )
return _baseAssetId = BaseAsset.Id;
return _baseAssetId;
}
set => _baseAssetId = value;
}
public int BaseAssetPrecision
{
get;
set;
}
public long QuoteAssetId
{
get
{
if( QuoteAsset != null )
return _quoteAssetId = QuoteAsset.Id;
return _quoteAssetId;
}
set => _quoteAssetId = value;
}
public int QuoteAssetPrecision
{
get;
set;
}
#endregion
#region Navigation Properties
public virtual Asset BaseAsset
{
get;
set;
}
public virtual Asset QuoteAsset
{
get;
set;
}
#endregion
}
public class Trade : EntityBase
{
#region Properties
public decimal Price
{
get;
set;
}
public decimal Quantity
{
get;
set;
}
public decimal QuoteQuantity
{
get;
set;
}
public long Timestamp
{
get;
set;
}
public bool IsBuyer
{
get;
set;
}
public DateTime Time
{
get => Timestamp.ToUnixTimeMilliseconds();
}
#endregion
}
这是UnitOfWork接口的方式:
public interface IRepository<TEntity> : IDisposable
where TEntity : IEntity, new()
{
Task AddAsync( TEntity entity, CancellationToken cancellationToken = default );
Task<TEntity> GetByIdAsync( long id, CancellationToken cancellationToken = default );
Task<bool> RemoveAsync( TEntity entity, CancellationToken cancellationToken = default );
Task<bool> UpdateAsync( TEntity entity, CancellationToken cancellationToken = default );
}
答案 0 :(得分:2)
一个简单的解决方案是将所有交易存储在同一张表中,为Symbol创建一个外键列,并为Id和Symbol列创建一个唯一的复合索引。但是,我很犹豫,因为我最终将存储超过10亿笔交易,而且这种方法仍然会给我当前的存储库模式设计带来问题。
这就是答案。使用一个表并与您的符号列进行区分。由于几乎完全相同的表中的重复项,因此将它们分开的缺点是性能(主要是由于联接)和“规范化”