Оновлення таблиці з мільйонами записів минуло 4 дні


12

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

Я перевірив, чи монітор активності показує, що запит працює.

У журналі подій взагалі немає помилок.

Продуктивність:

  • Tempdb на диску A (850 Гб вільного місця)
  • файл бази даних на диску B (вільний простір 750 гб)
  • 16 ГБ оперативної пам’яті

Підкажіть, будь ласка, що мені робити?

Запит

UPDATE
    dbo.table1
SET 
    costPercentage = ISNULL(t2.PaymentIndex, 1.0),
    t2.TopUp_Amt = (ISNULL(t2.PaymentIndex, 1.0) - 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00),
    Total_Tariff_Inc_t2 = ISNULL(t2.PaymentIndex, 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00)
FROM
    dbo.table2 t2
WHERE
    LEFT(dbo.test1.procodet, 3) = LEFT(t2.ProviderCode, 3) COLLATE database_default 

Відповіді:


3

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

Ймовірна причина полягає в тому, що з'єднання між двома таблицями створює надзвичайну кількість рядків. Це може статися, якщо LEFT(col, 3)вираз створює повторювані значення. Якщо він створить 10 дублікатів, це призведе до результату 100000x100000 = 10000000000 рядків.

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

Інша вірогідна причина - це недооцінка кардинальності вхідних чи вихідних даних. SQL Server, можливо, обрав цикл приєднання.

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


8

Цей запит вимагає сканувати кожну рядок таблиці, оскільки

  • Я думаю, що procodet або ProviderCode не індексуються
  • Навіть якщо вони були індексовані, у вас є ЛІФТ, який є функцією в предикаті WHERE
  • І у вас також є COLLATE, що ефективно є функцією предиката WHERE

"функція предиката WHERE" означає, що індекси не будуть використовуватися

Якщо ви його пакетно (скажімо, в UPDATE TOP (10000) ... AND costPercentage IS NULL), тоді вам потрібен індекс за costPercentage, і це припускає, що ви його встановлюєте.

Я бачу єдині рішення

  • заповнити нову таблицю партіями на основі, скажімо, первинного ключа
  • створити індексовані, обчислені стовпці, щоб приховати вирази LEFT та COLLATE, а потім запустити оновлення

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

1
Чому на сканування "мільйонів" рядків знадобиться 4 дні? Незалежно від того, якими великими та сильно індексованими можуть бути рядки, це не повинно зайняти 4 дні. Корінь проблеми досі невідомий.
usr

1
Якщо ви регулярно займаєтесь великими даними, що з цим отримати відповідний сервер для цього? Покладіть дані на SSD тощо.
TomTom

1
@Lucky впевнений. Я звертався до відповіді. Є щось не так, що ми ще не знайшли. Це не запит сам по собі або обладнання. Це ніколи не становитиме 4 дні тривалості.
usr

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

4

Перш за все, змініть запит на:

UPDATE t1
SET 
    costPercentage = ISNULL(t2.PaymentIndex, 1.0),
    t2.TopUp_Amt = (ISNULL(t2.PaymentIndex, 1.0) - 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00),
    Total_Tariff_Inc_t2 = ISNULL(t2.PaymentIndex, 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00)
FROM
  dbo.table1 t1
  inner join dbo.table2 t2
    on LEFT(t1.procodet, 3) = LEFT(t2.ProviderCode, 3) COLLATE database_default 

Як вказує перший пост Джеффа Модена в цій дискусії , ваш запит дуже схожий на той, який він попередив про "ефект Хеллоуїна".

Після цього ці ліві вирази необхідно проіндексувати. Відповідь gbn дає вам вказівки, як це зробити.

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