Яка з цих конструкцій столів найкраща для продуктивності?


16

Мене попросили створити щось, що відстежує щоденні витрати, що збираються на рахунках, і я намагаюся розробити схему таблиці баз даних, яка б це підтримувала.

Ось що я знаю

  • У компанії понад 2,5 мільйона рахунків
  • З них в даний час вони працюють в середньому 200 000 на місяць (що змінюється в залежності від рівня персоналу, який наразі низький)
  • У них є 13 різних типів витрат, які вони хотіли б відстежувати, і вони попередили, що вони можуть додати більше у майбутньому
  • Вони хочуть відстежувати витрати щодня
  • Витрати не поділяються на весь інвентар. Вони або розділені на # облікових записів, які працюють на місяць (200 000), або користувачі можуть ввести ідентифікатори облікових записів, щоб застосувати вартість до групи облікових записів, або вони могли просто вказати, до яких облікових записів слід застосувати витрати.

Першою моєю думкою була нормалізована база даних:

Номер рахунку
Дата
CostTypeId
Сума

Моя проблема з цим полягає в тому, щоб зробити математику. Ця таблиця швидко вийде величезна. Якщо припустити, що всі 13 типів витрат застосовуються до всіх відпрацьованих рахунків за поточний місяць, 200k * 13 * N days in monthце приблизно 75-80 мільйонів записів на місяць або близько мільярда записів на рік.

Друга моя думка полягала в тому, щоб трохи денормалізувати це

Номер рахунку
Дата
Загальна вартість
Тип витрат1
CostType2
Тип витрат3
Тип витрат4
Тип витрат5
Тип витрат6
Тип витрат7
Тип витрат8
Тип витрат9
Тип витрат10
Тип витрат11
Тип витрат12
Тип витрат13

Цей метод є більш денормалізованим і може створювати до 6 мільйонів записів на місяць ( 200k * N days in month), або близько 72 мільйонів на рік. Це набагато менше, ніж перший метод, проте якщо компанія в майбутньому зважиться на новий тип витрат, потрібно буде додати ще один стовпець бази даних.

З двох методів, яким ви віддаєте перевагу? Чому? Чи є інша альтернатива, яку ви можете придумати, яка б впоралася з цим краще?

Мене найбільше цікавлять звіти про результати роботи, як літній, так і детальний звіти. Робота, яка розподіляє витрати на рахунки, буде виконуватися вночі, коли нікого немає. Другою проблемою є розмір бази даних. В існуючій базі даних вже майже 300 ГБ, і я вважаю, що місце на диску становить близько 500 ГБ.

База даних - SQL Server 2005


Тож отримайте ще один диск. Диски дешеві. Ви можете мати 2 ТБ за вартість зустрічі, щоб сперечатися з цього приводу.

Відповіді:


9

Мільярд записів на рік - це не так багато.

З розділенням (можливо за типом Costtype) та архівуванням керувати ним.

Кількість елементів для зберігання даних все ще становить 200 к * 13 * Н. У стовпцях ви отримаєте менше рядків на сторінці, і це займе більше місця, ніж як рядки. Ви можете отримати, якщо "CostType1" не є типом даних фіксованої довжини, але є граничним.

"KISS", як кажуть


3
@Rachel Я напевно рекомендую реалізувати схему розділення з таким великим набором даних. Якщо вони зосереджуються на роботі в місяць і місяці, то найкраще вибрати ключ розділу, який може збігатися з таким мисленням. Крім того, якщо ви правильно налаштували свій розділ, ви можете легко переключати дані з та в таблицю для складання таблиць, що робить великі навантаження даних і видалення для прокатки даних, що забирає секунду замість годин.
Девід

6

Хоча ваш дизайн, безумовно, може змінити ніч або день, в цьому випадку я б більше зосередився на індексах, включаючи покриття індексів за потребою. Я також хотів би розглянути деякі інструменти, які надає вам SQL Server для роботи з дуже великими таблицями, наприклад, розділення таблиць.

Подумайте про це так, навіть якщо в таблиці є 80 мільярдів записів, при правильній індексації ті, які вас насправді цікавлять у будь-який момент, будуть згруповані фізично на диску. Через те, як організовані дані на SQL-сервері, дані, розділені за межами індексу, також можуть бути в іншій таблиці, оскільки йому не потрібно читати всю таблицю, щоб отримати необхідне.

Якщо ви також вирішите розділити таблицю, ви можете покращити час доступу та вставити час.


4

Я б нормалізував. Ми проводили облік витрат з прибутковістю рахунку клієнтів у банку, і ми генерували понад 250 мільйонів рядів індивідуальних витрат, використовуючи сотні водіїв, які розподілялися за центром витрат або за основною книгою, або різними іншими методами за мільйонами рахунків щомісяця.

Наприклад, загальна вартість обслуговування банкоматів була розподілена між рахунками, які використовували банкомати, виходячи з відносної кількості використання. Отже, якщо на обслуговування банкоматів витратили 1 мільйон доларів, і лише 5 клієнтів користувалися ним один раз, а один клієнт використовував їх 5 разів, то один клієнт коштував банку в 1,5 мільйона доларів, а інші клієнти коштували банку в 1 мільйон доларів кожен. Інші драйвери можуть бути набагато складнішими.

Зрештою, напевно, ви виявите це рідкісним - певні рахунки не отримують витрат від певних джерел / драйверів - а деякі рахунки нічого не отримують. У нормалізованій моделі цих рядків не існує. У денормалізованій моделі рядок існує з деякими порожніми стовпцями. Крім того, у розрідженій нормованій моделі слід побачити покращення продуктивності, оскільки існування рядка, як правило, швидше перевірити (з індексом покриття на CostType), ніж перевірка всіх рядків з не-NULL у певному "відрі" (навіть із індекси кожного стовпчика суми - який ви можете бачити, стає дуже марнотратним).


РІЗНАЧЕННЯ - Це дуже хороший момент, який має усе значення. Якщо це мало, ви заощаджуєте простір шляхом нормалізації. Інакше ні. Але дисковий простір дешевий, тому особисто я голосую за максимальну гнучкість (нормалізується).

3

Незалежно від переваги від виступу, я, безумовно, висловлюсь на користь варіанту 1. Варіант 2 пограбував би Петра заплатити Павлу, на мій погляд.


2

Я б пішов з варіантом 1, і тоді, якщо швидкість звітування стане проблемою вниз по дорозі, я також додаю таблицю 2 і заселю її в базу даних звітів в якомусь автоматизованому процесі ночівлі / позашвидкості.

Ви також можете розглянути можливість об'єднання щоденної структури таблиці 2 у подальші щотижневі, щомісячні, щоквартальні, щорічні збори, якщо це доцільно.

Але, як я вже сказав, я також вирішив би зберігати "необроблені" дані у належній (нормалізованій) формі.


0

З огляду на згадувані вами томи, я б пішов на другий варіант, але без TotalCost. Можна сказати, що все ще нормалізується.


Редагування: як альтернатива, і залежно від ваших вимог та розміру AccountId, ви також можете розглянути наступне:

AccountDate
-----------
AccountId  
Date  
AcDtID (surrogate key)

Costs
-------
AcDtID
CostTypeId  
Amount  

За допомогою цього дизайну ви все ще можете додати денормалізовану TotalCost до першої таблиці і перераховувати її щоночі, дозволяючи самостійно запускати деякі звіти.


У мене TotalCostє, тому що більшість звітів узагальнена, і я думав, що швидше буде запитувати одне значення, ніж додавати 13 різних значень.

Напевно, але тоді ви дійсно вводите перехідну залежність. Чи будуть коли-небудь оновлюватися ці записи? або просто написано і потім лише читати?

Записи оновлюються щоразу, коли до цього діапазону дат застосовується нова вартість. Приблизно через місяць малоймовірно, що загальна вартість оновиться, але все-таки це можливо завдяки таким речам, як щорічна плата за підтримку.

Тоді для кожного оновлення потрібно буде 2 оновлення, і поле TotalCost додає ризик невідповідності.

Перехідна залежність, але не обов'язково - ризик невідповідності - обмеження CHECK () може гарантувати, що TotalCost - це завжди сума витрат.
Майк Шеррілл 'Відкликання котів'

0

ви насправді повинні розділити таблицю ялинок на дві таблиці, щоб ви могли використовувати підзапит і вибрати другий рядок у вигляді стовпця чи багатьох стовпців. таким чином він є більш гнучким, і тим самим ви можете легше отримати результат, як другий.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.