Меня попросили создать что-то, что отслеживало бы ежедневную стоимость сбора на счетах, и я пытаюсь выяснить схему таблицы базы данных, которая бы это поддерживала.
Вот что я знаю
- Компания имеет более 2,5 миллионов счетов
- Из них в настоящее время они работают в среднем 200 000 человек в месяц (что зависит от уровня персонала, который в настоящее время является низким)
- У них есть 13 различных типов затрат, которые они хотели бы отслеживать, и они предупредили, что могут добавить больше в будущем
- Они хотят, чтобы расходы отслеживались ежедневно
- Затраты не распределяются по всему инвентарю. Они либо распределяются по количеству учетных записей, работающих в месяц (200 000), либо пользователи могут вводить идентификаторы учетных записей, чтобы применить стоимость к группе учетных записей, или они могут просто указать, к каким учетным записям применять стоимость.
Моей первой мыслью была нормализованная база данных:
AccountId Дата CostTypeId Количество
Моя проблема с этим, сделать математику. Этот стол станет огромным быстро. Предполагая, что все 13 типов затрат применяются ко всем работающим учетным записям в текущем месяце, это 200k * 13 * N days in month
примерно 75-80 миллионов записей в месяц или почти миллиард записей в год.
Моя вторая мысль была немного денормализовать
AccountId Дата Общая стоимость CostType1 CostType2 CostType3 CostType4 CostType5 CostType6 CostType7 CostType8 CostType9 CostType10 CostType11 CostType12 CostType13
Этот метод более денормализован и может создавать до 6 миллионов записей в месяц ( 200k * N days in month
), или около 72 миллионов в год. Это намного меньше, чем в первом методе, однако, если в будущем компания примет решение о новом типе затрат, потребуется добавить еще один столбец базы данных.
Из двух методов, которые вы предпочитаете? Почему? Есть ли другая альтернатива, о которой вы могли бы подумать, которая бы справилась с этим лучше?
Меня больше всего интересуют отчеты об исполнении, как обобщенные, так и подробные отчеты. Работа, которая будет распределять расходы по счетам, будет выполняться ночью, когда никого нет рядом. Вторая проблема - размер базы данных. Существующая база данных уже почти 300 ГБ, и я считаю, что место на диске составляет около 500 ГБ.
База данных SQL Server 2005
Ответы:
Миллиард записей в год - это немного.
С разделением (возможно для каждого типа затрат) и архивированием это можно сделать.
Количество элементов данных для хранения по- прежнему составляет 200k * 13 * N. В качестве столбцов вы получите меньше строк на страницу, и это займет больше места, чем в виде строк. Вы можете получить, если «CostType1» не является типом данных фиксированной длины, но он маргинальный.
"ПОЦЕЛУЙ" как говорится
источник
Хотя ваш дизайн, безусловно, может изменить ночное или дневное время, в этом случае я бы больше сосредоточился на индексах, включая покрытие индексов по мере необходимости. Я также хотел бы взглянуть на некоторые инструменты, которые SQL Server предоставляет вам для работы с очень большими таблицами, например, разбиение таблиц.
Подумайте об этом так, хотя в таблице 80 миллиардов записей с надлежащей индексацией, те, которые вам действительно интересны в любой момент, будут физически сгруппированы на диске. Из-за того, как данные организованы на сервере SQL, данные, разделенные по границам индекса, могут также находиться в другой таблице, потому что не нужно читать всю таблицу, чтобы получить то, что ей нужно.
Если вы также решили разделить таблицу, вы можете улучшить время доступа и время вставки.
источник
Я бы нормализовал. Мы провели учет затрат на прибыльность счета клиента в банке и сгенерировали более 250 миллионов строк отдельных расходов, используя сотни драйверов, которые распределялись по центрам затрат или по главной книге или различными другими методами на миллионы счетов каждый месяц.
Например, общая стоимость обслуживания банкоматов была разделена между счетами, которые использовали банкоматы, на основе относительного объема использования. Таким образом, если на обслуживание банкоматов было потрачено 1 миллион долларов, и только 5 клиентов использовали его один раз каждый, а один клиент использовал его 5 раз, то один клиент обошелся банку в 0,5 миллиона долларов, а остальные клиенты - банку в 0,1 миллиона долларов каждый. Другие драйверы могут быть намного сложнее.
В конечном счете, вы, вероятно, обнаружите, что он редок - некоторые учетные записи не получают затрат из определенных источников / драйверов - а некоторые учетные записи не получают ничего. В нормализованной модели эти строки не существуют. В денормализованной модели строка существует с несколькими пустыми столбцами. Кроме того, в разреженной нормализованной модели вы должны увидеть улучшение производительности, потому что наличие строки обычно проверяется быстрее (с индексом покрытия на CostType), чем проверка всех строк с ненулевым значением в определенном «сегменте» (даже при индексы на каждом столбце суммы - который вы видите, начинает становиться очень расточительным).
источник
Независимо от выигрыша в производительности, я определенно предпочел бы вариант 1. Вариант 2, по моему мнению, ограбил бы Питера, чтобы заплатить Полу.
источник
Я бы выбрал вариант 1, а затем, если бы скорость создания отчетов стала проблемой в будущем, я бы также добавил таблицу 2 и заполнил ее в базу данных отчетов с помощью какого-то автоматизированного процесса в течение ночи / вне периода.
Затем вы можете также рассмотреть возможность сворачивания ежедневной структуры таблицы-2 в последующие еженедельные, ежемесячные, квартальные, годовые сводки, если это будет оправдано
Но, как я уже сказал, я бы также решил хранить «сырые» данные в надлежащей (нормализованной) форме.
источник
Учитывая объемы, которые вы упоминаете, я бы выбрал второй вариант, но без TotalCost. Можно сказать, что все еще нормализовано.
Изменить: в качестве альтернативы, в зависимости от ваших требований и размера AccountId, вы также можете рассмотреть следующее:
При таком дизайне вы все равно можете добавить денормализованный TotalCost к первой таблице и пересчитать его ночью, что позволит запускать некоторые отчеты только для первой таблицы.
источник
TotalCost
в виду, потому что большая часть отчетов суммируется, и я подумал, что было бы быстрее запросить одно значение, чем добавить 13 различных значений.на самом деле вы должны разделить первую таблицу на две таблицы, чтобы вы могли использовать подзапрос и выбрать вторую строку в качестве столбца или нескольких столбцов. это более гибкий способ, и таким образом вы можете получить результат, подобный второму, легче.
источник