У нас є велика база даних, близько 1 Тб, що працює на SQL Server 2014 на потужному сервері. Все працювало чудово кілька років. Близько 2 тижнів тому ми провели повне обслуговування, яке включало: Встановити всі оновлення програмного забезпечення; відновити всі індекси та компактні файли БД. Однак ми не очікували, що на певному етапі використання процесора БД збільшилося більш ніж на 100% до 150%, коли фактичне навантаження було однаковим.
Після безлічі усунення несправностей ми звузили його до дуже простого запиту, але ми не змогли знайти рішення. Запит надзвичайно простий:
select top 1 EventID from EventLog with (nolock) order by EventID
Це завжди займає близько 1,5 секунд! Однак подібний запит з "desc" завжди займає близько 0 мс:
select top 1 EventID from EventLog with (nolock) order by EventID desc
PTable має близько 500 мільйонів рядків; EventID
- це первинний кластерний стовпчик індексу (упорядкований ASC
) з типом даних bigint (стовпець Identity). Існує кілька потоків, що вставляють дані в таблицю вгорі (більші EventID), і є 1 нитка видалення даних знизу (менші EventID).
У SMSS ми перевірили, що два запити завжди використовують один і той же план виконання:
Кластерне сканування індексів;
Орієнтовні та фактичні номери рядків - 1;
Орієнтовна та фактична кількість страт - це 1;
Орієнтовна вартість вводу / виводу - 8500 (здається, висока)
Якщо запускати послідовно, вартість запиту однакова 50% для обох.
Я оновив статистику індексу with fullscan
, проблема не зникала; Я знову відновив індекс, і проблема, здавалося, пішла на півдня, але повернулася.
Я включив статистику IO за допомогою:
set statistics io on
потім запустив два запити послідовно і знайшов таку інформацію:
(Для першого запиту, повільного)
Таблиця "PTable". Кількість сканувань 1, логічне зчитування 407670, фізичне зчитування 0, зчитування вперед-зчитування 0, логічне зчитування лобі 0, лобічне фізичне зчитування 0, лобічне зчитування вперед-0.
(Для другого запиту, швидкого)
Таблиця "PTable". Підрахунок сканування 1, логічне зчитування 4, фізичне зчитування 0, зчитування вперед-зчитування 0, логічне зчитування лобі 0, лобічне фізичне зчитування 0, лобічне зчитування попереднє зчитування 0.
Зауважте, величезна різниця в логічному читанні. Індекс використовується в обох випадках.
Фрагментація індексу може трохи пояснити, але я вважаю, що вплив дуже малий; і проблеми ніколи раніше не бувало. Ще один доказ - якщо я запускаю запит на зразок:
select * from EventLog with (nolock) where EventID=xxxx
Навіть якщо я встановив xxxx для найменших EventID в таблиці, запит завжди блискавично.
Ми перевірили, і немає проблем із блокуванням / блокуванням.
Примітка. Я просто намагався спростити проблему вище. "PTable" - це фактично "EventLog"; PID
є EventID
.
Я отримую те саме тестування результатів без NOLOCK
натяку.
Хтось може допомогти?
Більш детальні плани виконання запитів у XML:
https://www.brentozar.com/pastetheplan/?id=SJ3eiVnob
https://www.brentozar.com/pastetheplan/?id=r1rOjVhoZ
Я не думаю, що важливо надавати оператор create table. Це стара база даних, і вона тривала досконало протягом тривалого часу до технічного обслуговування. Ми самі провели багато досліджень і звузили їх до інформації, наданої моїм запитанням.
Таблиця створена зазвичай зі EventID
стовпцем як основним ключем, що є identity
стовпцем типу bigint
. В цей час, я думаю, проблема полягає в фрагментації індексу. Одразу після перебудови індексу проблема, здавалося, пішла на півдня; але чому воно повернулося так швидко ...?