设计多个表使用同一模型的SQL数据库

时间:2019-06-07 13:55:22

标签: c# postgresql database-design repository-pattern

背景

我正在尝试设计一个PostgreSQL数据库,该数据库将存储来自加密货币交易所的交易记录。我的客户中只有一个Trade模型,但想根据交易代表的符号将交易分为各自的表格。可用的符号在运行时推导,并且从交易所进行的交易每个都有自己的ID序列(从0开始)。

例如,说我想从Binance缓存交易。我的客户会调用他们的API,看到平台上可用的(一些)符号为BTCUSDTETHUSDTETHBTC,并且如果这些符号不在{ {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)创建一个外键列,并为SymbolId列创建一个唯一的复合索引。但是,我很犹豫,因为我最终将存储超过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 );

}

1 个答案:

答案 0 :(得分:2)

  

一个简单的解决方案是将所有交易存储在同一张表中,为Symbol创建一个外键列,并为Id和Symbol列创建一个唯一的复合索引。但是,我很犹豫,因为我最终将存储超过10亿笔交易,而且这种方法仍然会给我当前的存储库模式设计带来问题。

这就是答案。使用一个表并与您的符号列进行区分。由于几乎完全相同的表中的重复项,因此将它们分开的缺点是性能(主要是由于联接)和“规范化”