Хобрук: Ваш путь к мастерству в программировании

Дизайн таблиц и запросы

У меня есть дизайн стола, который представлен этим удивительным нарисованным от руки изображением.

введите здесь описание изображения

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

Все общие данные хранятся в таблице событий (Date, CreatedBy, Source Account Id...), а затем, если это транзакция, то данные, относящиеся к транзакции, хранятся в таблице транзакций учетной записи (третья сторона, тип транзакции (Debit, Credit).. .). Если событие является переводом, то конкретные данные о переводе находятся в таблице account_transfer (Amount, destination account id...).

Обратите внимание, что я забыл нарисовать, это то, что таблица событий имеет event_type_id. Если event_type_id = 1, то это транзакция. Если это 2, то это Перенос.

И таблицы переноса, и таблицы транзакций связаны с таблицей событий через внешний ключ идентификатора события.

Обратите внимание, что транзакция не имеет суммы, так как транзакция может быть разделена на несколько платежных строк, поэтому у нее есть дочерняя account_transaction_line. Чтобы получить сумму транзакции, вы суммируете ее дочерние строки.

Все внешние ключи настроены, с индексом первичных ключей...

Мой вопрос касается дизайна и запросов. Если я хочу перечислить все события для определенной учетной записи, я могу:

Select 
from Event, 
where event_type = 1 (transaction), 
then INNER join to the Transaction table,
 and INNER join to the transaction line (to sum the total)... 
 and then UNION to another selection, 
selecting 
from Event,
 where event_type = 2 (transfer),
 INNER join to transfer table... 
 and producing a list of all events.

or

Select 
from Event, 
then LEFT join to transaction, 
then LEFT join to transaction line,
 then LEFT join to transfer ... 
 and sum up totals (because of the transaction lines).

Что эффективнее? Я думаю, что вариант 1 лучше, так как он позволяет избежать ЛЕВЫХ соединений (сканирования?)

OR...

Индексированное представление варианта 1?

10.06.2014

  • Плюс 1 за нарисованную схему, но не вижу смысла в отдельных таблицах для переводов и транзакций. Если немного подумать о дизайне, ваши запросы могут быть намного проще. 11.06.2014
  • Я думал об одной таблице транзакций, но думал, что передача и транзакция кажутся разными. У них есть общие поля, но есть и много принципиальных отличий. Один отправляется третьей стороне (обнуляемый), у другого есть целевой счет (обнуляемый), транзакция может быть разделена на множество строк, где перевод является одним вкладышем (я также могу просто иметь строку для каждого перевода, а не сумму в таблице переноса). Я могу перейти на одну таблицу... но пытался избежать всех избыточных столбцов, допускающих значение NULL. Если это будет более эффективно, то я все еще могу изменить свой дизайн. 11.06.2014
  • Чтобы иметь единую таблицу, мне потребуются многочисленные соединения LEFT с моей третьей стороной, таблицей учетных записей (для учетной записи назначения)... тип транзакции (кредит/дебет) не потребуется для передачи (использует источник и место назначения). Добавление всех столбцов, допускающих значение NULL, принудительное левое соединение - разве это не менее эффективно? 11.06.2014

Ответы:


1

О производительности

Для анализа производительности SQL-сервера необходимо учитывать несколько факторов, например.

  • Какое количество запросов вы собираетесь выполнять, особенно. на одних и тех же данных? Например, если 80 % ваших запросов составляют около 20 % ваших данных, кэширование может значительно помочь. (См. ниже раздел дизайна о том, как это может иметь значение)
  • Ваши базы данных распределены или размещены на одном сервере? Я предполагаю, что это система с одним сервером, но если бы они были распределенными, дизайн и оптимизация могли бы отличаться.
  • Выполняются ли эти запросы в фоновом режиме или по запросу, и пользователь ожидает получить результаты быстрее?

Без этих (и, возможно, некоторых других дополнительных вопросов после получения ответов на них) было бы неразумно давать ответ о том, что один из них предпочтительнее другого.

Сказав это, исходя из моего личного опыта, лучше всего для сервера SQL использовать анализатор запросов, что на самом деле довольно разумно, в качестве первой остановки. После этого вы можете провести анализ производительности, чтобы найти оптимальное решение. Как правило, это делается путем моделирования трафика запроса таким, каким он был бы при система находится под постоянной нагрузкой. (К вашему сведению: моделирование связано с моделированием производительности ASP.NET, но различные основные концепции применимы и к SQL.) Обычно вы загружаете систему, а затем:

  • Посмотрите, сколько соединений потеряно — это может увеличиться, если запросы дорогие.
  • Счетчики производительности на сервере (ах), чтобы увидеть, как система справляется с нагрузкой.
  • Ответы на запросы, чтобы увидеть, не начинают ли некоторые из них давать действительный ответ, хотя это маловероятно.

К вашему сведению: это основано на моем личном опыте после проведения различных типов анализа производительности для нескольких проектов. Мы планируем сделать это снова для нашего текущего проекта, хотя на этот раз мы используем таблицы AD и Azure вместо SQL, и, следовательно, методология не специфична для SQL-сервера, хотя инструменты, профили трафика и то, что измеряется, различаются. .

О дизайне

Введение идентификатора события в строку транзакции учетной записи: Хотя вы не указываете это явно, но похоже, что идентификатор события и идентификатор транзакции не изменятся после того, как будет сделана первая запись. Если это так, и вы заинтересованы только в получении итогов для транзакции в этом запросе, то другим вариантом (который оптимизирует ваши запросы) будет добавление внешнего ключа к первичному ключу AccountEvent (который, я думаю, является идентификатором события) . В самом строгом смысле БД вы немного денормализуете таблицу, но на практике это часто помогает с производительностью.

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

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

Полная денормализовать: это еще один подход, который люди использовали (особенно в пространстве NOSQL), но он вызывает у меня дрожь при применении в SQL Server, поэтому у меня есть личное предубеждение против него, но вы мог бы очень хорошо поискать его и найти об этом.

11.06.2014
  • Спасибо @Омар. Я посмотрю, что вы говорите. Хранение вычисленных значений и добавление идентификатора события в таблицу строк транзакции кажется нарушением принципов проектирования, но может работать. Мне нужно расследовать это. Моя самая большая проблема с моим текущим дизайном, на великолепной диаграмме, - это ЛЕВЫЕ СОЕДИНЕНИЯ, которые мне понадобятся. Я не уверен в их производительности. Переход к одной таблице — еще один вариант, но опять же, будет множество пустых полей, требующих левых соединений. На самом деле борьба с вариантами. 11.06.2014
  • Конечно, нп. Наверное стоит прототипировать: можно было потратить день-два и создать 2-3 разные БД с разными опциями и попробовать их. Часто видеть в реальности имеет большое значение (сродни картинке тысяча слов :-)). Кроме того, я не уверен, по какому принципу проектирования сохраняются итоги в основной таблице? Вероятно, сформулировать плюсы и минусы в таблице также может помочь, потому что иногда мы также имеем дело с нашими личными предубеждениями в дополнение к реальным проблемам дизайна (таким как этот). 11.06.2014
  • Новые материалы

    Как свинг-трейдеры могут использовать ИИ для больших выигрышей
    По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

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

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..

    React Hooks: основы деструктуризации массива
    Kent C. Dodds написал классный пост о том, как грядущая функция React под названием Hooks работает на капоте. Предстоящий хук React useState основан на деструктурировании массива, давайте..

    Пакеты R, используемые в Tesla
    Добро пожаловать обратно! R — очень популярный язык программирования, используемый множеством компаний, включая Tesla! Итак, давайте взглянем на некоторые пакеты R, которые использует Tesla...

    Сокращение и слияние токенов для эффективных моделей VL: обзор
    Часто в задачах, связанных с компьютерным зрением и НЛП, вычислительно затратная и требующая большого объема памяти обработка становится препятствием для более быстрого логического вывода модели, а..