ВИБІРТЕ ТОП 1 із дуже великої таблиці в стовпці індексу дуже повільно, але не з зворотним порядком (“desc”)


17

У нас є велика база даних, близько 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. В цей час, я думаю, проблема полягає в фрагментації індексу. Одразу після перебудови індексу проблема, здавалося, пішла на півдня; але чому воно повернулося так швидко ...?

Відповіді:


18

Кластерне сканування індексів показує 423,723 логічних читання, щоб повернути перший рядок, займаючи 1926 мс:

Горіхи

Це здається досить багато, щоб знайти перший рядок у порядку індексу.

Швидше за все, ваша задача з очищення привидів біжить далеко за межі або зупинилася. Вам слід перевірити наявність ghost_record_countкластерного індексу в sys.dm_db_index_physical_statsта стежити за змінами в часі.

Замовило сканування з кінця індексу , який бачить постійні видалення будуть сканувати через дуже багато пунктирні записи , перш ніж він знаходить першу «живу» рядок повернення. Це пояснює зайві логічні читання. Шукання b-дерева до найнижчого значення індексу зіткнеться із значно меншими записами.

Ще одним фактором, що впливає на ефективність, є те, що саме сканування стає відповідальним за видалення записів привидів, як згадувалося в " Inside the Storage Engine": глибоке очищення привидів від Пола Рандала.

Ви повинні перевірити, чи прапор 661 сліду (вимкнути очищення привидів) не активний.

Рішення

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

У вашому конкретному випадку:

Виявилося, що проблема була викликана іншою тестовою базою даних на тому ж сервері. Ця тестова база даних була відновлена ​​з "втратою даних" і пошкоджена. Дивно, але процес очищення привидів, очевидно, застряг у цій базі даних. Після того, як ми видалили цю пошкоджену базу даних з SMSS, проблема вирішилася сама (зайняла тривалий час і, можливо, спричинила блокування БД на короткий час).

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