2013. február 17., vasárnap

Amikor nem jön a csoda

Üdvözletem mindenkinek!


Nemrég egy tanfolyamon kérték, hogy nézzünk már rá egy példát arra, amikor az index használata nem feltétlenül fogja csoda szerűen meggyorsítani a folyamatunkat úgy, ahogy azt elvárnánk tőle. Bár akkor is játszottunk a teszt környezetben, de most is bemásolok egy friss adatot egy mai szituból.


Adott egy tábla, benne kb 12-13 millió rekord.

Létre lett hozva egy non-clustered index egy string típusú mezőre. Legyen mondjuk a neve "M"
(Van clustered index is a táblán, de az most nem használható fel). Erre az indexre azért van szükség, mert sokszor lesz ún. "nagy szelektivitású" lekérdezés ezen mező segítségével.

Az index létrehozása kb 13 percig tartott.

Ezután nem sokkal jött az isteni sugallat, hogy van jónéhány olyan rekord, aminek az értéke ezen mezőn nem az igazi, ezért azt mad jól megápdételem.

update táblám SET M=NULL where datalength(M) > 20

Aztán csak vártam és vártam és vártam... :) Majd megkaptam azt hogy 3.558.279 row(s) affected.

Ja és ezt természetesen 15 és fél perc után.

Tehát elmondhatjuk, hogy az indextől nem várhatunk mindig csodát...

Miért is volt ez ennyire lassú?

Olyan "szerencsés" helyzetben vagyok, hogy több probléma is volt ezzel a lekérdezéssel:

1.: Az indexbe mi került bele? Hát maga a string tartalom... Én meg mit használok a feltételben? Egy int típusú számot, ami mellesleg a kulcs hossza, de hát kit érdekel, mivel azt szépen ki kell számolnia minden egyes esetben a datalength függvénnyel.

2.: Akárhogy is csűrjük-csavarjuk, ha 12 millió rekordból 3.5 milliót kezelned kell, az már nem annyi időbe kerül, mintha csak pár 10 ezret kezelnél...

Mi lehetett volna erre egy megoldás, így utólag belegondolva? :)

Talán lehetne az, hogy csinálni kell egy számított oszlopot, ami tartalmazza a hosszakat, na azzal lehetne szép gyorsulást elérni! Főleg ha dobunk rá egy indexet ;)


Kreatívabb ötlet a számított oszlopnál? Valaki?

(Természetesen ha az adattartalmat kellett volna vizsgálni, akkor jobban muzsikált volna az index.)


Bye.


2013. február 12., kedd

Rekord "karbantartás"

Sziasztok!


Nemrég esett meg velem, hogy egy syslog file 1 napnyi tartalmát importálni kellett MsSqlbe. Létre is jött egy szerény 5.000.000 darab rekordot tartalmzó import nevű tábla, ami ugye tartalmazott kőkemény 1 db oszlopot, ami egy valami-string típusú volt.

Aki még nem játszott sysloggal: Egy hatalmas,hosszú stringben tárolja el az összes adatot, amit megkapott valamilyen szolgáltatástól (pl Ips) Tehát ugyanabban a stringben fogod látni a dátumot, időt, forrás ip, cél ip, stbstb adatokat. Ugye milyen elegáns?

Szóval, gyorsan kiegészítettem egy id mezővel az import táblát, hogy mégis legyen egy clusterelt index is a családban. (Egyszer úgy kipróbálnám milyen jó játék lehet egy sok gigás adatbázist HEAP struktúrával üzemelteteni :)   )

Ezután futtatam egy ideig a scriptem, amit string-cincáló tárolt eljárásnak neveztem csak el.
(Egy ideig = Egy tisztességes adag amerikai kávét simán elkortyolgattam, mire végzett, dehát érthető is)


Ekkor már megvolt a cél táblám, ami tartalmazott mindenféle ID-t, forrás és cél ip címeket, dátumot, és más egyéb okosságokat.

Már kezdett megfogalmazódni bennem az "ez is megvan, még sincs este" szlogen amit egy cimborámtól szoktam volt kölcsönvenni, amikor megkopoktatták a vállamat, hogy ugyanmár, miért van a rekordok majd' felénél többszöröződés? Mint kiderült, a syslog is így kapta már meg az adatokat, noha ez engem nem vígasztalt, mivel a táblám így nem a valóságot tartalmazza...

Tehát most több millió rekordot nyálazzak át, hogy miben van egy, és miből több...

Eddig a prológus.


Mivel az első google találatok szvsz agyonbonyolított subkveris megoldásokkal akartak segíteni, inkább erőt vettem magamon, és nekiálltam gondolkodni.

Hogyan kellene kitörölni?

1.: Számoljuk meg hogy az X db mezők alapján hány egyforma rekord van.
2.: Ezt irassuk ki a táblával
3.: Ha ez a mennyiség több, mint 1, akkor törlés

Ahhoz hogy ez átlátható legyen, ja és nem mellesleg hatékony Execution Plannel működjön a CTE mellett voksoltam.

Íme:

with cte_tobb_azonos_rekord_torlese
as
(
select row_number() over(partition by source_ip,dest_ip,datum order by source_ip) as sorszam,
source_ip,dest_ip,datum
from adatbázis.dbo.táblám
)
delete from cte_tobb_azonos_rekord_torlese
where sorszam>1



Sziasztok!
Jó munkát! :)



2013. február 5., kedd

PIVOT / UNPIVOT / Tessék ? :)



Sziasztok!


Ha lenne egy felmérés arról, hogy mik azok a mondatok, amiket a legpontosabban mondanának el ugyanúgy az emberek,akkor szerintem a PIVOT fogalma jó eséllyel pályázhatna egy dobogós helyezésre!

Mi a Pivot? "Hááát, megfordítja 90 fokkal az adatokat, és az oszlopokból sorok lesznek, a sorokból meg oszlopok."

Nice.

-  És hogy működik a gyakorlatban?
-  És ha Pivotolok egy táblát, majd azt Unpivotolom (nekem a visszapivotolás sokkal jobban tetszene) akkor az eredeti értékeket kapom vissza vajon, vagy nem?
-  És ...


Nézzük meg:


Készítünk egy játszós táblát (sql2012 szintaktika), ami mondjuk a Snooker játékosokat fogja tárolni, és azt, hogy ezek a profik melyik pontszerző tornát nyerték meg és mennyiszer.

Azok kedvéért elmondom, akik kevésbé szeretik a snookert, hogy minden évben minden tornát megrendeznek, és világbajnokság is minden évben van.

CREATE TABLE Snooker(Nev VARCHAR(35), Torna VARCHAR(40), Menny INT)


INSERT Snooker(Nev,Torna,Menny) VALUES('Sullivan','VB',2),

VALUES('Sullivan','China Open',2),
VALUES('Sullivan','Masters',4),
VALUES('Sullivan','British Open',1), 
VALUES('Trump','Masters',1),
VALUES('Trump','British Open',3),

VALUES('Sullivan','VB',4)


Nézzünk egy alap lekérdezést :

Select * from Snooker

Nev                   Torna             Menny
-------------------------------------------------
Sullivan               VB                 2  
Sullivan               China Open         2
Sullivan               Masters            4
Sullivan               British Open       1
Trump                  Masters            1
Trump                  British Open       3
Sullivan               VB                 4





Nézzünk egy Pivot lekérdezést a Tornákra vonatkozóan:


SELECT Torna,Sullivan,Trump
FROM (
SELECT Nev, Torna, Menny FROM Snooker) abc
PIVOT (SUM(Menny) FOR Nev IN (Sullivan, Trump)) AS pvt
ORDER BY Torna



Torna      Sullivan     Trump 
------------------------------------------------------------------
British Open          1                     3
China Open           2                     NULL
Masters                 4                     1
VB                        6                     NULL


És ezt már lehet is kiexportálni excelbe! :)



Példa az Unpivotra:

SELECT Torna,Sullivan,Trump
FROM (
SELECT Nev, Torna, Menny FROM Snooker) abc
PIVOT (SUM(Menny) FOR Nev IN (Sullivan, Trump)) AS pvt
UNPIVOT (Menny FOR Nev IN (Sullivan, Trump))  As unpvt



Név                    Torna           Mennyiség
---------------------------------------------------

Sullivan               VB                 6  
Sullivan               China Open         2
Sullivan               Masters            4
Sullivan               British Open       1
Trump                  Masters            1
Trump                  British Open       3



Konklúzió: Az utolsó példában is lehetett látni, hogy aggregált függvények miatt simán előfordulhat az, hogy a Pivot utána Unpivot nem állítja elő nekünk az eredeti adatokat! 



Hajrá Pivot! :)


Transaction Log backup vs. Log shipping

Üdv Nektek!



Csörög a telefonom. Hív egy hallgatóm, hogy segítsek már ötletelni, mi lehet a nyűgje az Sql szerverüknek...

Van pár adatbázisuk, amire be akartak konfigolni egy log shippinget. Mindemellett van egy jól működő Maintenance Planjük is. A log shipping megy-megy, aztán egyszer csak elhasal. De hogy még színezzük egy kicsit, nem mindegyiken hasal el, csak az 50%-án :)


Na akkor nézzük sorjában:

1.: Mit csinál a log shipping? Kér egy primary és egy secondary szervert, prim. szerveren levő adatbázisról készül egy Full Backup, az átkerül a a sec. szerverre és visszaállítjuk. Ez után pedig elkezdődik a transaction log mentése, átvitele majd visszaállítása a sec. szerveren. (Ezt 3 db job látja el)

2.: A log shippingelt adatbázisoknak muszáj FULL vagy BULK- LOGGED recovery módban lennie, hogy értelmezve legyen a tranzakciós log file mentése. (Mert ez Simple módban nincs)

3.:A Maintenace Plan tartalmaz tran log mentést is "természetesen".

4.:Mi fog történni a log shipping konfigolása után?

Mivel ugyanarról az adatbázisról két külön job is tran log mentést fog csinálni, ezért szét fog cincálódni a tran log LSN-je, és a log shipping el fog hasalni!



Megoldás:


Azoknál az adatbázisoknál, ahol log shippinget tervezünk, a Maintenance Planben csak Full Backup vagy Differential Backup műveletet végezzünk, és hagyjuk hogy a tranzakciós log mentését a log shipping végezze el!

Ha szükségét érezzük a tran logok gyűjtésének, akkor figyeljünk arra, hogy a backup retention period értéke elég nagy legyen, és egyszerűen másoljuk le a log shipping megosztott könyvtárából a log fileokat egy számunkra megfelelő helyre.

Ha nem csökken a tran log mérete, akkor a dbcc shrinkfile paranccsal lehet rajta segíteni!
(De akkor Full recovery modellben legyen az adatbázis, amikor shrinkelünk)


Ami az X-akta az esetben, az az, hogy miért csak az 50% hasalt vajon el? Nem tudom, mert nem láttam élőben a környezetet, de szinte biztos, hogy ott nem voltak adottak ugyanezek a folyamatok.


Végül, ha már egyszer elszúrtúk a tran log LSN-jént, akkor készítsünk egy Full Database Backupot, és a továbbiakban rendben leszünk.


Szép napot ! :)