Должен ли я проектировать базу данных SQL Server, чтобы полагаться на UNION или избегать ее? - PullRequest
3 голосов
/ 06 апреля 2011

Возьмите следующий SQL-запрос:

SELECT     Account, Amount AS Deposit, 0.00 AS Withdrawal, Date
FROM       Deposits
WHERE      Account = @Account
UNION
SELECT     Account, 0 AS Expr1, Amount, Date
FROM       Withdrawals
WHERE      Account = @Account
ORDER BY   Date Desc

В отличие от:

SELECT    Account, TransactionType, Amount, Date
FROM      Transactions
WHERE     Account = @Account
ORDER BY  Date Desc

В первом запросе депозиты и снятие денег хранятся в разных таблицах и всегда, когда их нужно увидетьвместе, например, при предъявлении банковской выписки, они объединены вместе.Во втором запросе все транзакции, депозиты и снятия хранятся в одной таблице, а тип транзакции дифференцируется через столбец TransactionType.Результаты запроса не совсем совпадают, но предположим, что клиент доволен либо как конечный результат.

Есть ли какая-то причина производительности, почему настройка базы данных с использованием первой схемы лучше или хуже, чем второйсхема?

РЕДАКТИРОВАТЬ: просто для ясности, я хотел бы отметить, что причина, по которой я задавал этот вопрос, состоит в том, чтобы выяснить, есть ли производительность преимущество в ведении таблицменьше и используя UNION, когда это необходимо, по сравнению с одной большой таблицей, где я бы использовал предложение WHERE для поиска различных типов данных.Я использовал приведенный выше пример, чтобы лучше выразить свой вопрос.Совет по поводу того, какая схема лучше по другим причинам, приветствуется, но, пожалуйста, постарайтесь также ответить на вопрос.

Ответы [ 8 ]

4 голосов
/ 06 апреля 2011

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

Однако представьте, что вы хотите рассчитать остаток на счете в любой момент времени. Если у вас есть таблица «транзакции», вы можете достичь этого за один запрос -

select sum(amount) from transactions

Если вы разбили две таблицы, вам нужно выполнить два запроса; в общем, я ожидал бы, что это займет вдвое больше времени, чем запросы к одной таблице, даже если эта таблица имеет то же количество записей, что и две другие таблицы, вместе взятые.

Я думаю, вам следует сконцентрироваться на том, что лучше всего представляет бизнес-область - если вы посмотрите на старомодную бухгалтерскую книгу, я думаю, вы обнаружите, что как кредиты, так и дебеты указаны в одном столбце. Заинтересованные стороны вашего бизнеса с большей вероятностью будут думать с точки зрения «транзакции» - положительной или отрицательной - чем с точки зрения наличия отдельных концепций для депозитов и изъятий.

4 голосов
/ 06 апреля 2011

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

2 голосов
/ 07 апреля 2011

С точки зрения бухгалтерии, депозиты и снятие денег являются транзакциями с неподписанными суммами.Разница заключается в направлении движения денежных средств.Это склоняется к одной таблице транзакций, а не к отдельным таблицам пополнения и снятия.

С точки зрения моделирования ER / data, если мы начнем с вышеизложенного, тогда возникает вопрос: разделяют ли депозиты и изъятия один и тот же наборатрибуты?Если они это сделают, то у вас есть четкое указание на то, что они на самом деле являются одной и той же сущностью.Если они имеют разные атрибуты, то вы можете рассматривать разные подтипы: возможно, родительскую таблицу транзакций, содержащую общие атрибуты и подтаблицу для каждого типа транзакции:

create table dbo.TransactionBase
(
  id     int   not null primary key ,
  type   int   not null , -- 1:Deposit, 2:Withdrawal, 3:???, ...
  amount money not null ,
  -- ... other common attributes ,
)
create table dbo.TransactionDeposit
(
  transaction_id int not null
    primary key
    foreign key references dbo.TransactionBase(id) ,
  -- ... deposit-specific attributes
)
create table dbo.TransactionWithdrawal
(
  transaction_id int not null
    primary key
    foreign key references dbo.TransactionBase(id) ,
  -- ... withdrawal-specific attributes
)

В этой модели базовая транзакцияТаблица имеет отношение с количеством элементов от одного к нулю или единице между каждой из ее таблиц подтипов.Каждая транзакция существует в базовой таблице и только в одной из таблиц подтипов.

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

Это более важно, если вы видите увеличение количества типов транзакций.

2 голосов
/ 06 апреля 2011

Я бы пошел за Transaction таблицей. Это значительно упрощает реализацию базового класса Transaction в вашем приложении.

Если позже вы поймете, что вам нужны пользовательские столбцы WITHDRAWAL и DEPOSIT, вы можете создать таблицы подклассов, содержащие эти столбцы.

1 голос
/ 07 апреля 2011

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

Я работалс системой (разработанной кем-то другим), где разные типы расходов были в разных таблицах, и этот выбор вызвал много ошибок в течение многих лет, так как новые разработчики не знали, что они должны находить данные в нескольких таблицах.Я думаю, что отдельные таблицы здесь также были бы проблемой обслуживания, когда люди, делающие странный выбор в отношении того, как получить данные (включая использование UNION, где UNION ALL указывается по соображениям производительности), когда они должны быть простыми.

1 голос
/ 06 апреля 2011

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

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

1 голос
/ 06 апреля 2011

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

Обычно вы можете создать индексированное представление, если вас беспокоит производительность, но, к сожалению, поскольку вы используете союзы, вы не можете .Если вас беспокоит производительность, вы можете подумать о создании таблицы, загружаемой с объединенными данными.

0 голосов
/ 07 апреля 2011

Я лично пошел бы с двумя таблицами и использовал бы UNION ALL, если вам нужно сгруппировать результаты вместе.

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

Другими словами, если этот запрос объединения выполняется 100 раз в день, нообновления и обновления отдельных таблиц происходят 1000 раз в день, а затем держите их отдельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...