Прапор проти таблиці розділити


10

Я розробляю таблицю предметів, яка (потенційно) містить десятки мільйонів записів. Деякі елементи будуть недоступні для використання, поки адміністратор їх не "схвалить". Під "використанням" я маю на увазі, що такі елементи не будуть посилатися на будь-яку іншу таблицю, поки вони не будуть "затверджені". До 50% елементів можуть бути "не схвалено" в будь-який момент. Записи можуть стати "затвердженими", але не навпаки.

Я розглядаю два варіанти дизайну:

  • трохи прапор
  • окрема таблиця "не схвалених" елементів - коли елемент затверджено, він переміщується до "звичайної" таблиці (оновлення ідентифікатора елемента не є проблемою)

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

Питання: чи варто розглянути перший варіант (бітовий прапор) замість цього? Чи має в описаній ситуації переваги?


1
Це може допомогти пам’ятати, що ви можете використовувати відфільтровані індекси, щоб прискорити доступ до затверджених записів. brentozar.com/archive/2013/11/…
mendosi

На жаль, відфільтровані індекси не використовуються в параметризованих запитах.
Діма

@Dima, це не зовсім так. Якщо відфільтрований індекс має сказати, WHERE status='A'а запит має WHERE status = 'A' AND (... other columns and parameters here...), то індекс все ще може бути використаний.
ypercubeᵀᴹ

Відповіді:


6

Ви можете мати його обома способами з розділеними поданнями .

Ви створюєте підпорядковану таблицю для кожного статусу, забезпечену обмеженнями, з взаємовиключними значеннями. Потім вигляд, який об'єднав об'єднані таблиці. На вигляд або на кожну базову таблицю можна посилатися явно. Якщо статус рядка ОНОВЛЕНО за допомогою представлення, СУБД видалить його з однієї базової таблиці та вставить її в ту, що відповідає новому статусу. Кожну базову таблицю можна проіндексувати незалежно відповідно до її схеми використання. Оптимізатор вирішить посилання індексу на одну відповідну базову таблицю, якщо це можливо.

Переваги:
а) більш дрібні показники. Однак займайтеся математикою на фан-ауді. При такому масштабі та розділенні між вашими статусними значеннями можливо, що індекси будуть на тій же глибині таблиць такою ж глибиною, що і в комбінованій таблиці.
б) жоден код програми не повинен змінюватися. Дані продовжують відображатися як суцільне ціле.
в) майбутні нові значення статусу можна включити, додавши нову базову таблицю з обмеженням та повторно створивши подання.

Вартість - це все те, що рух даних; для кожного оновлення статусу записуються дві сторінки та пов'язані з ними індекси. Багато IO мати справу. Такий великий рух також спричинить роздробленість.


5

таблиця предметів, яка (потенційно) містить десятки мільйонів записів.

Це насправді не так вже й багато, враховуючи те, з чим SQL Server може ефективно впоратися. Звичайно, я пам’ятаю одну з моїх попередніх робіт, де одна з найбільших таблиць (система з одним примірником) мала 2 мільйони рядків, і це було найбільше, з чим я коли-небудь мав справу. Тоді в наступному завданні було 17 виробничих екземплярів, де деякі таблиці мали сотні мільйонів рядків, і всі вони були об'єднані в сховище даних з кількома таблицями фактів, що мають понад 1 мільярд рядків. Не зрозумійте мене неправильно, я не знущаюся з десятків мільйонів рядків, я лише підкреслюю, що за допомогою хорошої моделі даних та належного індексування (та обслуговування індексу) SQL Server може впоратися з багатьма .

До 50% елементів можуть бути "не схвалено" в будь-який момент.

Хм. Це не звучить правильно. Швидкість "схвалення" записів буде вдвічі меншою за швидкість отримання нових записів? На кожні 2 нові записи лише 1 буде "затверджено"? У вашому прикладі 2 мільйони рядків та 1 мільйон у кожному для "затверджених" та "неприйнятих", через кілька років із ще 10 мільйонами записів ви очікуєте по 6 мільйонів у кожному "затвердженому" та "не затвердженому"? Або це так, що 1 мільйон "не затверджених" залишиться дещо постійним, так що з 10 мільйонів нових записів буде 11 мільйонів "затверджених" і ще 1 мільйон "не затверджених"?

Записи можуть стати "затвердженими", але не навпаки.

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

Отже, давайте розглянемо вибір:

Прапор (або, можливо, навіть TINYINT"статус")

  • Трохи повільніше для запитів кожного статусу
  • Більш гнучка з часом / легко включити зміни, такі як третій стан (наприклад, "Заархівовано") лише з новим значенням статусу пошуку. Немає нової таблиці (обов'язково), якийсь новий код, лише якийсь код оновлений.
  • Менше роботи (тобто код, тестування тощо) та менше місця для оновлення помилок у одному TINYINTстовпчику
  • Менш складні = менші витрати на обслуговування з часом, коротший час навчання для нових працівників
  • (можливо) Менший вплив на Журнал транзакцій у міру оновлення однієї таблиці
  • Просто потрібна таблиця пошуку для "RecordStatus" і FK між двома таблицями.

Дві окремі таблиці (одна для «затверджених», одна для «не затверджених»)

  • Трохи швидше для запитів кожного статусу
  • Менш гнучкими з часом / важче включити зміни, такі як третій стан (наприклад, "Заархівовано"); новий стан зажадає, швидше за все, ще одну таблицю і, безумовно, новий і оновлений код.
  • Більше роботи (тобто код, тестування тощо) та більше місця для переміщення записів про помилки з таблиці "Не схвалено" до таблиці "Затверджено"
  • Складніше = більші витрати на обслуговування з часом, довший час навчання нових працівників
  • (можливо) Більший вплив на Журнал транзакцій, коли одна таблиця видалена, а одна вставлена
  • Не потрібно хвилюватися з приводу " відновлення ідентифікатора елемента ": У несанкціонованій таблиці є стовпець ідентифікатора, який є IDENTITYстовпцем, а затверджена таблиця має стовпчик ідентифікатора, який не є IDENTITY(як там він не потрібен). Значення ідентифікаторів залишаються послідовними при переміщенні запису між таблицями.

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


Це таблиця з швидко рухаються даними: досить часто заповнюється великою кількістю нових рядків, досить часто рядки видаляються. Я намагався видалити всі деталі (наприклад, бізнес-рішення, кодування клієнта тощо), щоб сконцентруватися лише на одній темі. В основному у нас є таблиця старого дизайну з трохи прапором. І я знаю на 100%, що рядки, у яких встановлено прапор 1, ніколи не використовуються в жодній іншій таблиці. Тому я відчуваю, що вони відбуваються лише там і можуть бути переміщені до окремого столу. Таблиця сканується майже за кожним запитом до БД. Таким чином, зменшення його «ваги» потенційно може зменшити ops CPU / IO.
Діма

3
Ще одна перевага розділених таблиць: Ви можете мати FK, які посилаються лише на таблицю "Затверджено".
ypercubeᵀᴹ

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