Ако някога сте използвали Management Studio, това изходно съобщение вероятно ще изглежда познато:
(1 ред(ове) засегнат)
Това идва от DONE_IN_PROC
на SQL Server съобщение, което се изпраща при успешното завършване на всеки SQL оператор, който е върнал резултат (включително извличането на план за изпълнение, поради което виждате две от тези съобщения, когато всъщност сте изпълнили само една заявка).
Можете да потиснете тези съобщения със следната команда:
SET NOCOUNT ON;
Защо направи това? Тъй като тези съобщения са разговорни и често безполезни . В моите презентации за лоши навици и най-добри практики често говоря за добавяне на SET NOCOUNT ON;
към всички съхранени процедури и го включва в кода на приложението, което изпраща ad hoc заявки. (По време на отстраняване на грешки обаче може да искате флаг, който да включва отново съобщенията, тъй като изходът може да бъде полезен в тези случаи.)
Винаги съм добавял отказ от отговорност, че съветът за включване на тази опция навсякъде не е универсален; зависи. Старите набори от ADO записи всъщност ги интерпретираха като набори от резултати, така че добавянето им към заявките след факта може действително да наруши приложенията, които вече ги пропускат ръчно. И някои ORMs (кашлица NHibernate кашлица ) всъщност анализира резултатите, за да определи успеха на DML командите (уф!). Моля, тествайте промените си.
Знам, че в един момент доказах на себе си, че тези бъбриви съобщения могат да повлияят на производителността, особено в бавна мрежа. Но мина много време и миналата седмица Ерин Стелато ме попита дали някога съм го документирал официално. Не съм, така че ето. Ще вземем много прост цикъл, при който ще актуализираме променлива в таблицата милион пъти:
SET NOCOUNT OFF; DECLARE @i INT = 1; DECLARE @x TABLE(a INT); INSERT @x(a) VALUES(1); SELECT SYSDATETIME(); WHILE @i < 1000000 BEGIN UPDATE @x SET a = 1; SET @i += 1; END SELECT SYSDATETIME();
Няколко неща, които може да забележите:
- Екранът за съобщения е наводнен с екземпляри на
(1 row(s) affected)
съобщение: - Началният
SELECT SYSDATETIME();
не се показва в панела с резултати, докато не завърши цялата партида. Това е заради наводнението. - Изпълнението на тази партида отне около 21 секунди.
Сега, нека повторим това без DONE_IN_PROC
съобщения, като промените SET NOCOUNT OFF;
за SET NOCOUNT ON;
и го стартирайте отново.
Въпреки че панелът за съобщения вече не беше наводнен със засегнатите редове(и), пакетът продължаваше да се изпълнява от ~21 секунди.
Тогава си помислих, чакай малко, знам какво става. Аз съм на локална машина, без включена мрежа, използвам споделена памет, имам само SSD и купища RAM...
Така че повторих тестовете, използвайки моето локално копие на SSMS срещу отдалечена Azure SQL база данни – Standard, S0, V12. Този път заявките отнеха много повече време, дори след намаляване на итерациите от 1 000 000 на 100 000. Но отново нямаше осезаема разлика в производителността дали DONE_IN_PROC
изпращани ли са съобщения или не. И двете партиди отнеха около 104 секунди и това можеше да се повтори при много итерации.
Заключение
Години наред работех с впечатлението, че SET NOCOUNT ON;
беше критична част от всяка стратегия за изпълнение. Това се основава на наблюдения, които направих в, може би, различна епоха и е по-малко вероятно да се проявят днес.
Въпреки това ще продължа да използвам SET NOCOUNT ON
, дори ако на днешния хардуер няма забележима разлика в производителността. Все още се чувствам доста силно за минимизиране на мрежовия трафик, където е възможно. Трябва да обмисля да внедря тест, при който имам много по-ограничена честотна лента (може би някой има AOL CD, който може да ми даде?), или да имам машина, където обемът на паметта е по-нисък от ограниченията на изходния буфер на Management Studio, за да съм сигурен, че има не е потенциално въздействие в най-лошия случай. Междувременно, въпреки че може да не промени възприеманата производителност на приложението ви, все пак може да помогне на портфейла ви винаги да включва тази настройка, особено в ситуации като Azure – където може да бъдете таксувани за изходящ трафик.