Яка відповідна архітектура індексу, коли змушена реалізувати IsDeleted (м'які делети)?


17

На даний момент у нас є існуюча база даних та програма, яка повністю функціонує. У мене немає можливості змінити архітектуру в цей момент. Сьогодні в кожній таблиці бази даних є поле "IsDeleted" NOT NULL BIT із замовчуванням "0". Коли програма "видаляє" дані, вона просто оновлює прапор IsDeleted до 1.

У мене виникають проблеми з розумінням того, як мають бути структуровані індекси кожної з таблиць. Зараз кожен запит / приєднання / тощо завжди реалізує чек IsDeleted. Це стандарт, якого повинні дотримуватися наші розробники. Зважаючи на це, я намагаюся визначити, чи потрібно змінити всі мої кластеризовані індекси первинного ключа в кожній із таблиць, щоб вони включали первинний ключ І поле IsDeleted BIT. Крім того, оскільки ВСЯКИЙ запит / приєднатися / тощо. повинен реалізувати перевірку IsDeleted, чи є доречним припущення, що ВСЕ єдиний індекс (також некластеризований) повинен включати поле IsDeleted як перше поле індексу?

Ще одне моє запитання - це відфільтровані індекси. Я розумію, що я міг би поставити фільтри на індекси типу "WHERE IsDeleted = 0", щоб зменшити розмір індексів. Однак, оскільки для кожного з'єднання / запиту доведеться реалізувати перевірку IsDeleted, чи не завадить це використано відфільтрований індекс (оскільки стовпець IsDeleted використовується при приєднанні / запиті)?

Пам'ятайте, я не маю можливості змінювати підхід IsDeleted.

Відповіді:


13

Найпростіший підхід тут - залишити свої ключі та кластерні індекси в спокої та використовувати відфільтровані індекси для своїх некластеризованих індексів.

Крім того, ви можете перенести кілька великих таблиць до купівлі розділених груп або до сховищ з розділеними стовпцями (SQL Server 2016+), залишивши первинний ключ та унікальні індекси нерозподіленими. Це дозволить вам натиснути неклавішні стовпці для рядків IsDeleted до окремої структури даних, яку можна додатково стиснути або зберігати в іншій групі файлів.

І переконайтеся, що розробники використовують літерал замість параметра для фільтрації рядків IsDeleted. З параметром SQL Server повинен використовувати один і той же план запитів для обох випадків.

EG

SELECT ... WHERE ... AND IsDeleted=0

І ні:

SELECT ... WHERE ... AND IsDeleted=@IsDeleted

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


Враховуючи всюдисутність та важливість IsDeletedстовпця, незалежно від фізичного зберігання, можливо, було б доцільно викрити дані через два представлення (необов'язково в різних схемах), вирішивши як питання параметризації, так і помилки з доступом до даних, які не повинні були бути звертатися менш імовірно. Доступ до базових даних є актуальним лише для рідкісних випадків, коли видалені та не видалені дані потрібно якось об'єднати, а коли рядки насправді потрібно переключити на "видалені".
Jeroen

@JeroenMostert хороша порада. Тут також можна використовувати RLS або щось на зразок EF Core Global Query Filters. docs.microsoft.com/en-us/ef/core/querying/filters
Девід Браун - Майкрософт

9

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

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

Інший варіант - створити індексований вигляд, який можна використовувати за допомогою ряду різних запитів, який фільтрується лише до не видалених рядків. Це може бути особливо корисним у Enterprise Edition, де автоматичне узгодження індексованого перегляду працює без надання NOEXPANDпідказки.

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


2

За обґрунтованим припущенням, що видалення є рідкісним, ніякі зміни в індексах не є відповідним рішенням.

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

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


0

Я бачив систему, де прапор IS_DELETED або 0, або значення PK. В інших системах це був мінус ПК.

Оскільки більшість запитів отримували значення за допомогою "природного" чи ділового (іноді багатопольового) ключа, вони ніколи не запитували ПК, за винятком приєднання; але вони завжди додавали AND IS_DELETED = 0 в кінці для основної таблиці та для будь-яких об'єднаних таблиць.

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


0

Сподіваюся, у вас є право та можливість змінювати запит.

Однак, оскільки для кожного з'єднання / запиту доведеться реалізувати перевірку IsDeleted, чи не завадить це використано відфільтрований індекс (оскільки стовпець IsDeleted використовується при приєднанні / запиті)?

Я хотів сказати один важливий момент, сподіваюся, що я зміг це пояснити.

У складному запиті, де Transaction tableі Masterобидва використовуються таблиці.

Використовувати IsDeleted=0тільки в Transactionтабл. Не використовуйте в Masterтаблиці.

Приклад,

Select * from dbo.Order O
inner join dbo.category C on o.categoryid=o.categoryid
inner join dbo.Product P on P.Productid=o.Productid
where o.isdeleted=0

Немає сенсу c.isdeleted=0(використовувати в Categoryтаблиці). Це зайве.

Аналогічно чи є якийсь сенс використання P.isdeleted=0?

Тому що я хочу, щоб усі нерегламентовані замовлення та їх деталі

Як можна Productвидалити, коли Orderє Activeабо де Productidє посилання.

Таким чином, якщо ви обережно налагодите важливий запит, тоді, можливо, ви можете видалити частину isdeleted = 0.

Не сліпо створюйте відфільтрований індекс, спочатку виберіть усі ці дуже важливі та повільні запити.

Оптимізуйте цей повільний запит, а потім вирішіть лише про відфільтрований індекс або налаштуйте індекс.

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