Що краще для великих змін таблиці: ВИДАЛИТИ та ВСТАВИТИ щоразу або ОНОВЛЕННЯ наявних?


27

Я роблю проект, де мені потрібно щодня змінювати записи в 36K в одній таблиці. Мені цікаво, що буде краще:

  1. видалити рядки та вставити нові, або
  2. оновити вже наявні рядки

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

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

Чи слід видаляти / вставляти записи чи слід оновлювати існуючі (де це можливо) для цього нічного процесу?


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

Відповіді:


9

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

Тепер, якщо значення в усіх 20 стовпцях змінюються АБО, навіть якщо дані в 5 стовпцях змінюються, і ці 5 стовпців індексуються, то вам може бути краще "видалити та вставити". Але якщо лише 2 стовпці змінюються і дозволяють сказати, що вони не є частиною жодних некластеризованих індексів, то вам може бути краще «Оновити» записи, оскільки в цьому випадку буде оновлений лише кластерний індекс (і індекси не доведеться оновлюватись).


Під час подальших досліджень я виявив, що наведений мною коментар є щось надмірним, оскільки SQL Server внутрішньо має два окремі механізми для виконання UPDATE. - "оновлення на місці" (тобто, змінивши значення стовпців на нове в початковому рядку) або як "НЕ на місці" ОНОВЛЕННЯ "(DELETE з наступною ВСТАВКОЮ).

Оновлення на місці є правилом і виконуються, якщо можливо. Тут рядки залишаються точно в тому самому місці на одній сторінці в однаковій мірі. Зачеплені лише байти, які постраждали. У tlog є лише один запис (за умови, що немає тригерів оновлення). Оновлення відбуваються на місці, якщо купа оновлюється (і на сторінці достатньо місця). Оновлення також трапляються на місці, якщо кластерний ключ змінюється, але рядок взагалі не потрібно переміщувати.

Наприклад: якщо у вас є кластерний індекс прізвища і у вас є імена: Able, Baker, Charlie. Тепер ви хочете оновити Baker на Becker. Жодних рядків не потрібно переміщувати. Тож це може відбутися на місці. Тоді як, якщо вам доведеться оновити Able до Kumar, рядки доведеться зміщувати (хоча вони будуть на одній сторінці). У цьому випадку SQL Server зробить DELETE з наступним ВСТУП.

Враховуючи вищесказане, я б запропонував вам зробити звичайне ОНОВЛЕННЯ та дозволити SQL Server з'ясувати найкращий спосіб, як це зробити всередині країни.

Для отримання більш детальної інформації про "ОНОВЛЮВАННЯ" внутрішніх справ або з цього приводу будь-яких внутрішніх служб, пов'язаних з SQL сервером, перегляньте книгу Калена Делані, Пола Рандала та ін. - " Внутрішні системи SQL Server 2008" .


8

Ви досліджували команду MERGE у SQL 2008? Ось основний приклад:

  merge YourBigTable ybt
  using (select distinct (RecordID) from YourOtherTable) yot
     on yot.Recordid = YBT.RecordID
  when NOT matched by target
  then  insert (RecordID)
        values (yot.DeviceID) ;

Це в основному команда "UPSERT". Оновіть, якщо він існує, вставте його, якщо його немає. ДУЖЕ швидко, дуже класна команда.


1
Це не швидше, ніж ОНОВЛЕННЯ, та сама механіка під капотом.
Марк Сторі-Сміт

Це швидше, ніж оновлення, а потім вставлення тих, які ще не існували.
datagod

2
Якщо ви знаєте, що це так, доведіть це :)
Марк Сторі-Сміт

4

Але я сам перевірив Видалити та вставити проти оновлення на таблиці, що містить 30 мільйонів (3 крори) записів. У цій таблиці є один кластеризований унікальний складовий ключ та 3 некластеризовані клавіші. Для видалення та вставки знадобилося 9 хв. Для оновлення знадобилося 55 хв. У кожному рядку оновлено лише один стовпець.

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


Я також потрапив у цей випадок, але потім виявив, що іноді вдається оптимізувати велике злиття, додавши покажчики (temp або perm) до джерела або цілі, підказки або підстановки цілі (не застосовується для повного злиття).
crokusek

3

Оновлення не так швидко. Хитрість полягає в тому, щоб досягти швидкої вставки - відключити індекси під час вставки даних.

Подумайте про використання цього:

-- disable indexes
ALTER INDEX [index_name] ON dbo.import_table DISABLE
-- ... disable more indexes

-- don't use delete if you don't care about minimal logging. truncate is faster
TRUNCATE TABLE dbo.import_table

-- just insert the new rows
INSERT dbo.import_table
SELECT
    *
FROM
    dbo.source_table

-- rebuild indexes
ALTER INDEX [index_name] ON dbo.import_table REBUILD
-- ... rebuild more indexes

Ще швидше - також вимкнути автоматичне оновлення статистики в параметрах db. Якщо таблиця істотно змінена, слід запустити:

UPDATE STATISTICS dbo.import_table

або

EXEC sp_updatestats

як робота на регулярній основі (щодня, щотижня, залежно від розміру дБ), щоб постійно оновлювати статистику. На що слід звернути увагу - це оновлювати статистику, коли таблиця порожня. Це накрутить статистику, якщо ви не запустите її після повторного заповнення таблиці.


4
Я не згоден, що це завжди так. Також таблиця у запитанні @ adopilot не може бути очищена TRUNCATE, оскільки вона містить 89м записів, і він хоче оновити лише 36k.
Марк Сторі-Сміт

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