Разработка базы данных SQL, в которой несколько таблиц используют одну модель - PullRequest
0 голосов
/ 07 июня 2019

Фон

Я пытаюсь создать базу данных PostgreSQL, в которой будут храниться торговые записи с бирж криптовалюты. У меня есть одна Trade модель в моем клиенте, но я хотел бы разделить сделки на их собственные таблицы на основе символа, который они представляют. Доступные символы выводятся во время выполнения, и каждый из сделок с биржи имеет свою собственную последовательность Id, начинающуюся с 0.

Например, скажем, я хочу кэшировать сделки из Binance. Мой клиент вызывал бы их API, видя, что (некоторые) символы, доступные на платформе, являются BTCUSDT, ETHUSDT и ETHBTC, и если эти символы еще не находятся в таблице bn.Symbols, это будет вставить их, а также создать новую таблицу bn.Trades-SYMBOLNAME.

Я использую технический стек .NET Core 3 с Dapper и PostgreSQL.

Выпуск

Я видел несколько постов, подробно описывающих, как написать процедуру или функцию, которая создает таблицу с предоставленной переменной в качестве имени, и похоже, что это плохой дизайн .

В дополнение к этому негативному настроению, мой клиент использует шаблоны репозитория и единицы работы, и TradeRepository взаимодействует таким образом, что определяет метод GetById(long), поэтому я не могу указать, какой символ мне нужен в репозитории. к цели, и я не могу указать символ в функциях репозитория, не прибегая к некоторым грязным трюкам.

Простым решением было бы сохранить все сделки в одной таблице, иметь столбец внешнего ключа для Symbol и создать уникальный составной индекс для столбцов Id и 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

}

Вот как все хранилища связаны:

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 );

}

А вот как интерфейс UnitOfWork:

public interface IUnitOfWork : IDisposable
{

  #region Properties

  Guid Id
  {
     get;
  }

  IDbConnection Connection
  {
     get;
  }

  IDbTransaction Transaction
  {
     get;
  }

  #endregion

  #region Repositories

  IAssetRepository Assets
  {
     get;
  }

  ITradeRepository Trades
  {
     get;
  }

  ISymbolRepository Symbols
  {
     get;
  }

  #endregion

  #region Public Methods

  void Begin();
  void Commit();
  void Rollback();

  #endregion

}

1 Ответ

2 голосов
/ 07 июня 2019

Простым решением было бы сохранить все сделки в одной таблице, иметь столбец внешнего ключа для Symbol и создать уникальный составной индекс для столбцов Id и Symbol. Однако я не решаюсь сделать это, потому что в конечном итоге я буду хранить более миллиарда сделок, и этот подход также все еще вызывает проблемы с моим текущим дизайном шаблона репозитория.

Это ответ. Используйте одну таблицу и различайте ее по столбцу символов. Недостатками их разделения являются производительность (в основном из-за объединений) и «нормализация» из-за дублирования в таблицах, которые в значительной степени идентичны

...