Питання, яке виникло під час обговорення в чаті:
Я знаю, що хеш-приєднання вимикає перемикання внутрішньо на якусь штуку вкладених циклів.
Що робить SQL Server для виклику сукупного хеш- пакету (якщо це може статися взагалі)?
Питання, яке виникло під час обговорення в чаті:
Я знаю, що хеш-приєднання вимикає перемикання внутрішньо на якусь штуку вкладених циклів.
Що робить SQL Server для виклику сукупного хеш- пакету (якщо це може статися взагалі)?
Відповіді:
Обидва хеш-об'єднання та хеш-агрегат використовують один і той же код оператора, хоча хеш-агрегат використовує лише один (збірний) вхід. Основна робота агрегату хеша буде описана Craig Freedman :
Як і у випадку хеш-об'єднання, хеш-агрегат вимагає пам'яті. Перед виконанням запиту за допомогою хеш-агрегату, SQL Server використовує оцінки кардинальності, щоб оцінити, скільки пам’яті нам потрібно для виконання запиту. За допомогою хеш-з'єднання ми зберігаємо кожен ряд збірки, тому загальна потреба в пам'яті пропорційна кількості та розміру рядків збирання. Кількість рядків, що з'єднуються, і вихідна кардинальність з'єднання не впливають на вимогу пам'яті об'єднання. За допомогою хеш-агрегату ми зберігаємо по одному рядку для кожної групи, тому загальна потреба в пам'яті фактично пропорційна кількості та розміру вихідних груп або рядків. Якщо у нас менше унікальних значень групи за стовпчиками та меншою кількістю груп, нам потрібно менше пам’яті. Якщо у нас є більше унікальних значень групи за стовпчиками та іншими групами, нам потрібно більше пам’яті.
Він продовжує говорити про хеш-рекурсію:
Отже, що станеться, якщо у нас не вистачить пам’яті? Знову ж таки, як приєднання хешу, якщо у нас не вистачить пам’яті, ми повинні почати розсипати рядки до tempdb. Ми розливаємо одне чи більше відра чи розділів, включаючи будь-які частково агреговані результати разом з будь-якими додатковими новими рядками, які є хеш-кодом до розлитого відра або розділів. Хоча ми не намагаємось зібрати нові прокладені рядки, ми робимо їх хеш-поділ і розділяємо їх на кілька відрів або розділів. Після того, як ми закінчимо обробку всіх груп введення, ми виводимо завершені групи пам'яті і повторюємо алгоритм, читаючи назад і агрегуючи по одному розбитий розділ за один раз. Розділивши розбиті рядки на кілька розділів, ми зменшуємо розмір кожного розділу і, таким чином, зменшуємо ризик, що алгоритм потрібно буде повторити багато разів.
Допомога хешу легко задокументована, але Начо Алонсо Портільо згадує у " Який максимальний рівень рекурсії для ітератора хешу перед тим, як примусити вирядити?
Значення є постійним, жорстко закодованим у продукті, а його значення - п'ять (5). Це означає, що перш ніж оператор сканування хешу вдасться до алгоритму на основі сортування для будь-якого даного підрозділу, який не вписується у надану пам'ять з робочої області, повинно відбутися п'ять попередніх спроб розділити оригінальний розділ на менші розділи.
Згаданий "оператор сканування хешу" є посиланням на внутрішній клас CQScanHash
в sqlmin.dll
. Цей клас очолює реалізацію хеш-оператора (у всіх його формах, включаючи часткові агрегати та різні потоки), які ми бачимо у планах виконання.
Це приводить нас до основи ваших питань - що саме робить алгоритм порятунку? Це "сортування на основі" чи "базується на вкладених петлях"?
Це, мабуть, і те, і інше, в залежності від вашої точки зору. Коли хеш-рекурсія досягає рівня 5, хеш-розділ в пам'яті змінюється від хеш-таблиці до спочатку порожнього індексу b-дерева на хеш-значеннях. Кожен рядок з одного раніше розсипаного хеш-розділу розглядають в індексі b-дерева та вставляють (нова група) або оновлюють (підтримуючи агрегати) у відповідних випадках.
Ця серія невпорядкованих вставок у b-дерево може однаково добре розглядатися як сортування вставки або як індексований пошук вкладених циклів.
У будь-якому випадку, цей алгоритм резервного копіювання гарантовано завершиться з часом, не виділяючи більше пам'яті. Може знадобитися кілька пропусків, якщо місця, доступного для b-дерева, недостатньо для вміщення всіх ключів групування та агрегатів із переливного розділу.
Після того, як пам'ять, доступна для зберігання індексу b-дерева, вичерпується, усі подальші рядки (з поточного розлитого розділу) надсилаються до одного нового tempdb- розділу (який гарантовано буде меншим) і процес повторюється у міру необхідності. Рівень розливу залишається на рівні 5, оскільки закінчилася рекурсія хешу . Деякі деталі обробки можна спостерігати з недокументованим прапором 7357 сліду.