Database
 sql >> база данни >  >> RDS >> Database

Какво влияние могат да имат различните опции на курсора?

Няколко пъти съм писал за използването на курсори и как в повечето случаи е по-ефективно да пренапишете курсорите си с помощта на логика, базирана на набор.

Все пак съм реалист

Знам, че има случаи, в които курсорите са „задължителни“ – трябва да извикате друга съхранена процедура или да изпратите имейл за всеки ред, изпълнявате задачи за поддръжка на всяка база данни или изпълнявате еднократна задача, която просто не си струва да инвестирате време за преобразуване в базирано на набор.

Как (вероятно) го правите днес

Независимо от причината, поради която все още използвате курсори, трябва най-малкото да внимавате да не използвате доста скъпите опции по подразбиране. Повечето хора започват курсорите си така:

DECLARE c CURSOR FOR 
  SELECT whatever FROM ...

Сега отново, за ad-hoc, еднократни задачи, това вероятно е добре. Но има...

Други начини да го направите

Исках да изпълня някои тестове, използвайки настройките по подразбиране и да ги сравня с различни опции на курсора, като LOCAL , STATIC , САМО ЗА ЧЕТЕНЕ и FAST_FORWARD . (Има много опции, но това са най-често използваните, тъй като са приложими за най-често срещаните видове операции с курсор, които хората използват.) Не само исках да тествам суровата скорост на няколко различни комбинации, но също и въздействието върху tempdb и паметта, както след рестартиране на студена услуга, така и при топъл кеш.

Заявката, която реших да подавам към курсора, е много проста заявка към sys.objects , в примерната база данни на AdventureWorks2012. Това връща 318 500 реда в моята система (много скромна 2-ядрена система с 4 GB RAM):

SELECT c1.[object_id] 
  FROM sys.objects AS c1
  CROSS JOIN (SELECT TOP 500 name FROM sys.objects) AS c2;

След това увих тази заявка в курсор с различни опции (включително настройките по подразбиране) и проведох някои тестове, измервайки общата сървърна памет, страниците, разпределени към tempdb (според sys.dm_db_task_space_usage и/или sys.dm_db_session_space_usage ) и обща продължителност. Също така се опитах да наблюдавам tempdb конкуренцията, използвайки скриптове от Глен Бери и Робърт Дейвис, но в моята нищожна система не можах да открия каквото и да е спор. Разбира се, аз също съм на SSD и абсолютно нищо друго не работи в системата, така че това може да са неща, които искате да добавите към собствените си тестове, ако tempdb е по-вероятно да бъде пречка.

Така че в крайна сметка заявките изглеждаха така, с диагностични заявки, включени в подходящи точки:

DECLARE @i INT = 1;
 
DECLARE c CURSOR
-- LOCAL
-- LOCAL STATIC
-- LOCAL FAST_FORWARD
-- LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
  SELECT c1.[object_id] 
    FROM sys.objects AS c1
    CROSS JOIN (SELECT TOP 500 name FROM sys.objects) AS c2
    ORDER BY c1.[object_id];
 
OPEN c;
FETCH c INTO @i;
 
WHILE (@@FETCH_STATUS = 0)
BEGIN
  SET @i += 1; -- meaningless operation
  FETCH c INTO @i;
END
 
CLOSE c;
DEALLOCATE c;

Резултати

    Продължителност

    Може би най-важната и често срещана мярка е "колко време отне?" Е, отне почти пет пъти повече време за стартиране на курсора с опциите по подразбиране (или само с LOCAL посочен), в сравнение с уточняването на STATIC или FAST_FORWARD :

    Памет

    Исках също да измеря допълнителната памет, която SQL Server ще поиска при изпълнение на всеки тип курсор. Затова просто рестартирах преди всеки тест за студен кеш, като измервах брояча на производителността Обща памет на сървъра (KB) преди и след всеки тест. Най-добрата комбинация тук беше LOCAL FAST_FORWARD :

    използване на tempdb

    Този резултат беше изненадващ за мен. Тъй като дефиницията на статичен курсор означава, че той копира целия резултат в tempdb и всъщност се изразява в sys.dm_exec_cursors като СНИМКА , очаквах хитът на tempdb страници да бъде по-висок с всички статични варианти на курсора. Това не беше така; отново виждаме приблизително 5X удар при използване на tempdb с курсора по подразбиране и този само с LOCAL посочено:

Заключение

От години наблягах, че следната опция винаги трябва да се посочва за вашите курсори:

LOCAL STATIC READ_ONLY FORWARD_ONLY

От този момент нататък, докато имам възможност да тествам допълнителни пермутации или да намеря случаи, когато това не е най-бързият вариант, ще препоръчвам следното:

LOCAL FAST_FORWARD

(Като настрана, аз също проведох тестове, пропускайки LOCAL опция и разликите бяха незначителни.)

Въпреки това, това не е непременно вярно за *всички* курсори. В този случай говоря единствено за курсори, при които четете данни само от курсора, само в посока напред и не актуализирате основните данни (или чрез ключа, или с помощта на WHERE CURRENT OF ). Това са тестове за друг ден.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как AI ще промени разработката и тестването на софтуер

  2. Как да създадете една таблица от друга таблица в SQL

  3. Работа с не-ASCII JDBC данни в Talend

  4. Използване на Microsoft DiskSpd за тестване на вашата подсистема за съхранение

  5. Вашето окончателно ръководство за SQL присъединяване:INNER JOIN – Част 1