Навигация по сайту

Популярные статьи

Нататкі Дзмітрыя Пилюгина аб Microsoft SQL Server

  1. прыклад
  2. Адрозненне ад сцяга 2340

Адзін з даступных алгарытмаў злучэння двух табліц у SQL Server гэта укладзеныя цыклы (Nested Loops). У залежнасці ад абранага аптымізатарам парадку злучэння табліц, адна з табліц выбіраецца як знешняя (па ёй адкрываецца знешні цыкл), другая як унутраная (для кожнай радкі з знешняй табліцы выконваецца ўнутраны цыкл па другой табліцы), падчас злучэння, ўнутры цыклаў правяраецца ўмова злучэнне , такі падыход называецца «наіўны» алгарытм ўкладзеных цыклаў. Калі ж па ўнутранай табліцы даступны індэкс па ўмове злучэння, то неабавязкова выконваць унутраны цыкл праверкі па кожнай радку другой табліцы, замест гэтага, можна перадаць у якасці аргументу пошуку значэнне з знешняй табліцы, а ўсе радкі, што будуць знойдзеныя ва ўнутранай табліцы злучыць са радком з знешняй табліцы.

Пошук па ўнутранай табліцы - гэта выпадковы доступ, SQL Server пачынаючы з версіі 2005 мае аптымізацыю, званую batch sort (не блытаць з аператарам Sort ў Batch Mode для колоночных індэксаў). Ідэя аптымізацыі заключаецца ў тым, каб перад тым, як атрымаць дадзеныя з унутранай табліцы, упарадкаваць ключы пошуку з знешняй, ператварыўшы тым самым выпадковы доступ у паслядоўны.

Аперацыя batch sort не бачная ў плане запыту, як асобны аператар, замест гэтага, вы можаце назіраць ў аператары Nested Loops ўласцівасць Optimized = true. Калі б можна было ўбачыць batch sort як асобны аператар у плане, гэта б выглядала прыкладна наступным чынам:
Аперацыя batch sort не бачная ў плане запыту, як асобны аператар, замест гэтага, вы можаце назіраць ў аператары Nested Loops ўласцівасць Optimized = true

У дадзеным «псеўда-плане», мы чытаем дадзеныя з некластерного індэкса ix_CustomerID ў парадку ключа гэтага індэкса CustomerID, пасля чаго, нам неабходна выканаць Key Lookup ў кластарны індэкс (бо індэкс ix_CustomerID не з'яўляецца пакрывае для запыту, па якім атрыманы дадзены «псеўда-план»). Key Lookup - гэта аперацыя пошуку па ключы кластэрнага індэкса, выпадковы доступ, і каб ператварыць яго ў паслядоўны сервер можа выканаць batch sort па ключы кластэрнага азначніка.

Падрабязней па batch sort вы можаце пачытаць у маім англамоўным блогу, у артыкуле Batch Sort and Nested Loops .

Гэтая аптымізацыя дае добрае паскарэнне пры дастатковай ліку радкоў, вы можаце азнаёміцца ​​з вынікамі тэставання эфекту гэтай аптымізацыі ў блогу аднаго з распрацоўшчыкаў аптымізатар Крэйга Фрыдмана OPTIMIZED Nested Loops Joins .

Аднак, калі радкоў менш, чым чакалася, то дадатковыя выдаткі CPU на пабудову гэтай сартавання могуць прыглушваць яе выгады, павялічваць спажыванне працэсара і запавольваць выкананне. Да з'яўлення падказкі DISABLE_OPTIMIZED_NESTED_LOOP Microsoft прапаноўвала ў такім выпадку скарыстацца сцягам трасіроўкі 2340, ён адключае гэтую аптымізацыю. Цяпер, у гэтым няма неабходнасці і мы можам выкарыстоўваць хинт DISABLE_OPTIMIZED_NESTED_LOOP.

прыклад

Разгледзім прыклад:

use tempdb; go - Створым тэставую табліцу (SalesOrderID - кластарны ПК) create table dbo.SalesOrder (SalesOrderID int identity primary key, CustomerID int not null, SomeData char (200) not null); go - запоўніць яе тэставымі дадзенымі with n as (select top (1000000) rn = row_number () over (order by (select null)) from sys.all_columns c1, sys.all_columns c2) insert dbo.SalesOrder (CustomerID, SomeData) select rn% 500000, str (rn, 100) from n; - Створым некластерный індэкс create index ix_c on dbo.Salesorder (CustomerID); go - Па змаўчанні аптымізацыя batch sort ўключаная (Nested Loops: Optimized = true) select * from dbo.SalesOrder with (index (ix_c)) where CustomerID <1000; - Адключаем яе хинтом DISABLE_OPTIMIZED_NESTED_LOOP (Nested Loops: Optimized = false) select * from dbo.SalesOrder with (index (ix_c)) where CustomerID <1000 option (use hint ( 'DISABLE_OPTIMIZED_NESTED_LOOP')); go

Вынік:
Вынік:

Звярніце ўвагу на розны парадак радкоў пры вывадзе, бо у нас не зададзены відавочны парадак пры дапамозе ORDER BY, сервер вяртае радок у ключавым парадку іх апрацоўкі. У першым выпадку, мы паслядоўна чытаем з індэкса ix_c, але для аптымізацыі выпадковых чытанняў з кластэрнага індэкса, сартуем па ключы кластэрнага індэкса SalesOrderID. У другім выпадку, сартаванне не адбываецца і чытання ідуць у парадку ключоў CustomerID ў некластерном індэксе ix_c.

Адрозненне ад сцяга 2340

Нягледзячы на ​​тое, што ў дакументацыі сцяг 2340 паказаны як эквівалент хинта DISABLE_OPTIMIZED_NESTED_LOOP, гэта не зусім так.
Нягледзячы на ​​тое, што ў   дакументацыі   сцяг 2340 паказаны як эквівалент хинта DISABLE_OPTIMIZED_NESTED_LOOP, гэта не зусім так

Разгледзім наступны прыклад, у якім пры дапамозе недакументаваная каманды UPDATE STATISTICS ... WITH PAGECOUNT, я падману аптымізатар, сказаўшы, што табліца займае больш старонак, чым на самай справе. Не прынцыпова выкарыстоўваць менавіта гэтую каманду, можна было проста зрабіць табліцу шырэй, але я хачу зэканоміць час. Пасля гэтага, паглядзім на тры запыту:

  1. без любых падказак (MAXDOP, дададзена для захавання просты формы плана);
  2. з хинтом DISABLE_OPTIMIZED_NESTED_LOOP;
  3. са сцягам трасіроўкі 2340.

- імітуючы шырокую табліцу update statistics dbo.SalesOrder with pagecount = 100000; go set showplan_xml on; go - 1. Без падказак select * from dbo.SalesOrder with (index (ix_c)) where CustomerID <1000000 option (maxdop 1); - 2. Хинт select * from dbo.SalesOrder with (index (ix_c)) where CustomerID <1000000 option (use hint ( 'DISABLE_OPTIMIZED_NESTED_LOOP'), maxdop 1); - 3. Сцяг трасіроўкі select * from dbo.SalesOrder with (index (ix_c)) where CustomerID <1000000 option (querytraceon 2340, maxdop 1); go set showplan_xml off; go

У выніку мы атрымаем наступныя планы:

У выніку мы атрымаем наступныя планы:

Ва ўсіх трох планах, Nested Loops мае ўласцівасць Optimized = false. Справа ў тым, што, павялічыўшы шырыню табліцы, мы павялічылі кошт доступу да дадзеных. Пры досыць высокай кошту, сервер можа вырашыць замест няяўнай batch sort, выкарыстоўваць відавочны аператар сартавання Sort, што ён і робіць у дадзеным выпадку. Мы назіраем гэта ў плане першага запыту.

У другім запыце, мы выкарыстоўвалі хинт DISABLE_OPTIMIZED_NESTED_LOOP, які адключае няяўнай batch sort, але ён таксама прыбірае і відавочную сартаванне асобным аператарам. У трэцім плане, мы бачым, што нягледзячы на ​​даданне сцяга 2340, аператар сартавання прысутнічае.

Такім чынам, хинт адрозніваецца ад сцяга тым, што адключае аптымізацыю па пераўтварэнні выпадковага доступу ў паслядоўны цалкам, па-за залежнасці ад таго, як сервер вырашыць яе рэалізаваць, з дапамогай няяўнай сартавання batch sort або з дапамогай асобнага аператара Sort.

У наступнай нататцы мы пагаворым пра хинты FORCE_LEGACY_CARDINALITY_ESTIMATION і FORCE_DEFAULT_CARDINALITY_ESTIMATION.

PS Планы ў гэтай нататцы могуць залежаць ад абсталявання, так, калі ў вас не атрымліваецца прайграць прыклады, паспрабуйце павялічыць або паменшыць памер слупка SomeData char (200) у вызначэнні табліцы dbo.SalesOrder.