Предговор
Има информационна система, която администрирам. Системата се състои от следните компоненти:
1. База данни на MS SQL Server
2. Сървърно приложение
3. Клиентски приложения
Тези информационни системи са инсталирани на няколко обекта. Информационната система се използва активно 24 часа в денонощието от 2 до 20 потребителя наведнъж на всеки обект. Следователно не можете да извършвате рутинна поддръжка наведнъж. Така че трябва да „разпространя“ дефрагментирането на индекса на SQL Server през целия ден, вместо да дефрагментирам всички необходими фрагментирани индекси с един удар. Това важи и за други операции.
Свойството за автоматично актуализиране на статистиката се задава в свойствата на базата данни. Освен това статистиката се актуализира на дефрагментирания индекс.
Проблем
Преди около година срещнах следния проблем:
От време на време всички запитвания се изпълняваха бавно. Трябва да се отбележи, че времето за забавяне беше произволно. Това се случи на всеки обект в случаен ден. Освен това, когато започнах да анализирам колко често се случват закъсненията (с помощта на профайлъра), установих, че те се случват всеки ден в произволен момент. Потребителите просто не винаги им обръщат внимание, а ги приемат като единственото произволно забавяне и след това системата отново работи бързо.
Решаване на проблема
Прегледах всички бавно изпълняващи се заявки. Най-странното беше, че всички заявки се изпълняваха бавно в произволен момент, дори най-простите, като извличане на последния запис от таблица с няколко хиляди реда.
Освен това изпълних следните стъпки:
1. Анализирах регистрационните файлове на MS SQL Server и Windows Server, но не можах да намеря причината за закъсненията.
2. Анализирах индекси (фрагментация и т.н.), добавих липсващите и премахнах неизползваните.
3. Анализирах заявките – някои заявки бяха подобрени.
4. Анализирах задачите в SQL Agent и не можах да свържа задачите с проблема със забавянето.
5. Анализирах задачите в Task Scheduler и не можах да свържа задачите с проблема със забавянето.
6. Profiler показа резултатите, но не и причината за закъсненията.
7. Направих проверка за блокиране – не бяха разкрити дълги блокирания.
В резултат на това прекарах повече от 3 месеца в неуспешното търсене на причината за случайни бавно изпълняващи се запитвания. Въпреки това разкрих един интересен факт – вместо индикатора Worker execution, индикаторът Elapsed wait се увеличи за всички заявки. Този факт ми даде идеята, че нещо не е наред с дисковете. Проверих ги – всичко беше наред.
Решение
За моя изненада случайно разкрих, че когато една заявка се изпълняваше бавно в приложението, тя се изпълняваше бързо в SSMS. Една статия помогна за решаването на проблема (поне подсказа идеята).
Абзац от статията:
На практика най-важната опция SET е ARITHABORT, тъй като стойността по подразбиране за тази опция е различна за приложенията и за SQL Server Management Studio. Това обяснява защо можете да откриете бавно изпълняваща се заявка във вашето приложение и след това да постигнете добра скорост, като я изпълните в SSMS. Приложението използва план, който е създаден за набор от стойности, които се различават от действителните правилни стойности. Докато ако изпълните заявката в SSMS, най-вероятно е кешът все още да няма план за изпълнение за ARITHABORT ON и следователно SQL Server ще изгради план за текущите ви стойности.
Разликата в изпълнението се дължи на параметъра SET ARITHABORT. За всички заявки, изпълнявани в SSMS, тази опция е активирана, а за заявки отвън (от приложения) – деактивирана. Не може да се активира дори с проста заявка за приложения:
SET ARITHABORT ON;
Последва луда идея – изчистване на процедурния кеш в момента на затваряне.
За последващата ръчна проверка трябва да напиша следното изявление преди заявката в SSMS:
SET ARITHABORT OFF;
Така ще симулираме работата на приложението. Когато заявката се изпълняваше дълго време, изчистих процедурния кеш. И това винаги е помагало. Преди изчистване на процедурния кеш, заявката може да продължи до 20-30 секунди, а след това – 0 секунди.
След това направих друг експеримент – почистване на целия процедурен кеш за цялата база данни на всеки час чрез SQL агент:
--cleaning the cache by database id DBCC FLUSHPROCINDB (@db_id);
След това всички заявки се изпълняваха много бързо (по-малко от 0,05 секунди). Имаше само някои събития до 5-10 секунди на изпълнение, но потребителите не забелязаха никакви прекъсвания. Освен това актуализирането на статистиката не подобри резултатите, така че деактивирах актуализирането на статистиката.
След още няколко месеца проучване открих, че се случват случайни прекъсвания, когато или кешът консумира всичко на сървъра и не е останало свободно място, или има свободна памет, но по-малко от 1 GB RAM или услугата MS SQL Server заема цялата разпределена RAM (чрез диспечера на задачите). Но второто събитие се случи само два пъти за цялото проучване.
Факт е, че буквално всичко се записва в кеша, докато кешът не винаги се освобождава навреме. Проблемът с кеша беше решен с програмата EmptyStandbyList.exe.
Конфигурирах това приложение чрез Task Scheduler да се изпълнява 1 път на всеки час. След цялата извършена работа вече повече от половин година няма прекъсвания на заявките за всички обекти.
Единственото нещо, което остава неясно, са редките случаи, когато една заявка спира за 5-10 секунди веднъж месечно в произволен ден и в произволно време. Имаше 4 такива случая и само на два обекта за половин година, когато услугата MS SQL Server заема цялата разпределена памет за кратък период от време.
По принцип няма нужда да се рови по-дълбоко, тъй като потребителите не забелязват никакви прекъсвания и всичко работи добре, но ако някой има някакви мисли, ще съм благодарен да сподели.
Тази статия е написана, за да помогне на тези, които се сблъскват с подобни проблеми, тъй като не намерих изчерпателен отговор в Интернет и прекарах много време в изучаване на проблема и намиране на решението.
Вижте също:
- Внедряване на индикатор за ефективност на SQL Server за заявки, съхранени процедури и тригери
- Автоматизиране на дефрагментирането на индекса в база данни на MS SQL Server
Полезен инструмент:
dbForge Query Builder за SQL Server – позволява на потребителите да създават бързо и лесно сложни SQL заявки чрез интуитивен визуален интерфейс без ръчно писане на код.