Recent comments

None


İçerik Ara











Yasal Uyarı
Bu sitede sunulan tüm bilgi ve dökümanlar Turgay Sahtiyan tarafından yazılmaktadır. Yazıların kaynak göstermek şartıyla kullanılması serbesttir.

© Copyright 2009-2013
Takvim
<<  Kasım 2018  >>
PaSaÇaPeCuCuPa
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
Keywords

29.04.2013 Pazartesi günü yapacağım webcast’in duyurusunu yapmak istiyorum.

SQL Server 2012 Upgrade ve Migration metodları üzerine konuşacağımız webcast saat 14:00’da başlayacak.

Özellikle halihazırda kullandığı SQL Server veritabanlarını SQL Server 2012’ye taşımak isteyenlerin katılmasını önerdiğim bu webcast’e aşağıdaki linki kullanarak kayıt olabilirsiniz.

https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032543843&Culture=TR-TR

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


SQL Server’da Istatistik Kavramı adlı makalemde İstatistikler hakkında detaylı bir şekilde konuşmuştuk. Kısaca özet geçmek gerekirse; İstatistikler, Query Optimizier tarafından sorgu planı oluşturulurken daha performanslı bir plan oluşturmak için kullanılan, tablodaki verinin dağılımını gösteren istatistik bütünüdür. İstatistikler sayesinde, sorgu planı (Query Plan) oluşturulurken sorgudaki where bloğunda kullanılan kolon için dönecek tahmini kayıt sayısı bulunur. Bulunan bu değer index’e erişim şeklini belirler. Temel amaç, datayı en hızlı ve en az maliyetli şekilde kullanıcının karşısına getirmektir.

[more]

Gene aynı makalede Auto_Update_Statistics database özelliğinin ne şekilde çalıştığından ve basic threshold değerinin kayıt sayısının %20+500 olduğundan bahsetmiştik. Yani örneğin 10.000 kayıttan oluşan bir tablomuz var ise ve bu tablodaki Col1 kolonu üzerine istatistik tanımlandıysa, Col1 kolonunu etkileyecek 2.500 güncelleme işleminden sonra istatistik ilk kullanılmak istendiği anda (örneğin select işleminde) otomatik olarak güncellenecektir.

İstatistikler doğru query plan oluşturulması için çok önemli olduğu için istatistiklerin olması kadar güncel olması da çok önem taşımaktadır. Bu yüzden best practice olarak Auto_Update_Statistics database özelliğinin açık olması önerilir. (Sharepoint gibi bazı database’lerde kapalı olması önerilmektedir) Fakat %20’lik threshold değeri oldukça fazla olduğundan çoğu durumda bu threshold değeri yakalanamamakta ve tablo çok fazla update görmesine rağmen istatistik update olmamaktadır. Örneğin 100.000.000 kayıttan oluşan bir hareket tablosundaki istatistiğin bu özellik sayesinde otomatik olarak update görmesi için yaklaşık 20.000.000 kaydın update olması gerekiyor ki reel hayatta böyle bir şey neredeyse mümkün değil.

İşte bu noktada karşımıza SQL Server 2008 R2 SP1 gelen 2371 Trace Flag’i çıkıyor. Bu trace flag aktif edildiğinde tablodaki kayıt sayısı arttıkça %20’lik threshold değeri daha erişilebilir seviyelere iniyor.

image

Kaynak : http://blogs.msdn.com/b/saponsqlserver/archive/2011/09/07/changes-to-automatic-update-statistics-in-sql-server-traceflag-2371.aspx

Yukarıdaki grafiği incelediğimizde tablodaki kayıt sayısı 25.000’ken %20’lik threshold geçerliyken, kayıt sayısı arttıkça %20’lik threshold aşağılara inmekte. Örneğin 100.000 kayıt sayısı için %10’lu değerlere, 1.000.000 kayıt için %3.2 gibi bir değere inmekte ki bu değerler artık yakalanabilir seviyelere gelmiş olmaktadır.

Özellikle çok büyük tablolarınız var ise (Örneğin SAP uygulaması, http://blogs.msdn.com/b/saponsqlserver/archive/2011/09/07/changes-to-automatic-update-statistics-in-sql-server-traceflag-2371.aspx) ve out of dated istatistiklerden dolayı performans sıkıntısı çektiğinizi düşünüyorsanız bu trace flag’i aktif hale getirmeyi düşünebilirsiniz.

Son olarak bir örnek yaparak trace flag’in davranışı görelim ve yazımıza son verelim.

--Bir calisma DB’si create ediyoruz
create database StatsDeneme
GO
use StatsDeneme
GO
--Auto_Create_Statistics ve Auto_Update_Statistics parametrelerini on yapiyoruz
alter database StatsDeneme set Auto_Create_Statistics ON
alter database StatsDeneme set Auto_Update_Statistics ON
--Bir calisma tablosu create ediyoruz
if OBJECT_ID('StatsDeneme','U') is not null
  drop table StatsDeneme
create table StatsDeneme(col1 int, col2 varchar(10), col3 varchar(5))
GO
--Calisma tablosuna rasgele 100.000 veri basiyoruz.
declare @i int=0
while @i<100000 begin
  insert StatsDeneme select @i,CAST(@i as varchar(10)),'a' + cast((@i % 10) as varchar(6))
  set @i=@i+1
end

--Istatistik olusturmak icin select sorgumuzu cekiyoruz
--Auto_Create_Statistics database ozelligi on oldugu icin
--	asagidaki sorgu sonucu col3 kolonu icin istatistik olusacaktir
select * from StatsDeneme where col3='a1'

--Istatistigin son guncellenme zamanina bakiyoruz
select object_name(object_id),name as StatsName,STATS_DATE(object_id,stats_id) 
from sys.stats
where object_name(object_id) = 'StatsDeneme'

--Trace Flag'i aktif etmeden 10.000 kaydi update ediyoruz (%10)
update top(10000) StatsDeneme set Col3 = 'xx' 

--Auto_Update_Statistics ozelligini tetiklemek icin select sorgusunu tekrar cekiyoruz
select * from StatsDeneme where col3='a1'

--Istatistigin son guncellenme zamanina tekrar bakiyoruz ve 
--	daha %20+500'luk threshold dolmadigi icin update olmadigini goruyoruz
select object_name(object_id),name as StatsName,STATS_DATE(object_id,stats_id) 
from sys.stats
where object_name(object_id) = 'StatsDeneme'

--10.500 kaydi daha update ediyoruz ve threshold'u yakaliyoruz (%20%500)
update top(10500) StatsDeneme set Col3 = 'xx' 

--Auto_Update_Statistics ozelligini tetiklemek icin select sorgusunu tekrar cekiyoruz
select * from StatsDeneme where col3='a1'

--Istatistigin son guncellenme zamanina tekrar bakiyoruz ve istatistigin update oldugunu goruyoruz
select object_name(object_id),name as StatsName,STATS_DATE(object_id,stats_id) 
from sys.stats
where object_name(object_id) = 'StatsDeneme'

--Dolayisiyla 2371 trace flag'ini kullanmadan threshold degerimiz %20+500
--Simdi ayni islemleri 2371 trace flag'ini aktif ederek tekrar yapalim

--Trace Flag'i aktif ediyoruz 
DBCC TraceOn (2371)

--Not:Trace flag'i bu sekilde aktif etmektense trace flag startup parametrelerine konularak 
--	SQL Server her acildiginda trace flag otomatik olarak aktif ettirilebilir)

--10.000 kaydi update ediyoruz (%10)
update top(10000) StatsDeneme set Col3 = 'yy' 

--Auto_Update_Statistics ozelligini tetiklemek icin select sorgusunu tekrar cekiyoruz
select * from StatsDeneme where col3='a1'

--Istatistigin update oldugunu goruyoruz. 
--%10'luk kisim update olmasına ragmen istatistigin update olma nedeni 2371 trace flag'ini aktif etmis olmamiz
select object_name(object_id),name as StatsName,STATS_DATE(object_id,stats_id) 
from sys.stats
where object_name(object_id) = 'StatsDeneme'

--calisma database'ini drop ediyoruz
use master
go
drop database StatsDeneme
Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


SQL Server’da birden fazla kolon üzerine tanımlanan index’lere composite index denilmektedir. Örneğin aşağıdaki index 2 kolon üzerine tanımlanmış nonclustered bir composite index örneğidir.

create nonclustered index IX_1 on tbl1
	(Column1, Column2)

 

Klasik Index’ler (ColumnStore Index’de durum farklıdır) B-Tree yapısında organize olduklarından dolayı index’in hangi sıralama ile oluşturulduğu oldukça önem taşımaktadır. Çünkü yukarıdaki index örneğini ele alırsak kayıtlar önce column1’e göre dizilecek, daha sonra column2’e göre dizelecektir. (Index’lerdeki B-Tree yapısı hakkında daha detaylı bilgi almak için şu makaleye göz atabilirsiniz)

[more]

Composite index oluştururken uyguladığımız ilk best practice where koşulundaki eşitlik (equality) kolonlarının eşitlik olmayan (inequality) kolonlardan daha önce yazılması gerektiğidir.

2. best practice’imiz ise her grubun içinde (eşitlik ve eşitlik değil) selectivity’si yani seçiciliği daha fazla olan kolonun daha önde tanımlanmasıdır. Örneğin kişi bilgilerini tuttuğumuz bir tabloda cinsiyet ve il alanlarına index tanımlayacağımızı ve sorgumuzda cinsiyet ve il alanlarını eşitlik şeklinde kullandığımızı düşünelim. Cinsiyet alanı sadece 2 farklı değer alabilirken il alanı 81 farklı değer alabilmektedir. Dolayısıyla il alanının seçiciliği cinsiyet alanine göre çok daha fazladır. Bu yüzden bu 2 kolon için composite index tanımlanacaksa sıralamanın il,cinsiyet şeklinde olması gerekir.

Best practice’leri toplayacak olursak;

  • «Eşittir» kolonları «eşit değil» kolonlarından önce kullanılmalıdır.
  • En seçici «eşittir» kolonu ilk sıraya konulmalıdır.
  • En seçici «eşit değildir» kolonu son «eşittir» kolonundan sonraya konulmalıdır.

Örneğin aşağıdaki gibi bir sorgu için index create ediyorsak ve col2, col4 kolonları diğer kolonlara göre daha seçiciyse index’in şu şekilde olması best practice’dir

Select * from tbl1_
where Col1<>'a' and Col2='b' and Col3='c' and Col4<>'d'

create nonclustered index IX_1 on tbl1
	(Col2, Col3, Col4, Col1)

 

Şimdi bir örnek yaparak konuyu pekiştirelim.

--Bir calisma tablosu olusturuyoruz
Create table tbl_CompSample(Gender char(1), City int, Col1 Char(50), Col2 Char(50))
go

--Calisma tablosuna 1000 kayit basiyoruz
declare @i int = 1
while @i<1000 begin
	insert tbl_CompSample 
		select (case @i%2 when 1 then 'M' else 'F' end), (@i%81)+1, 'value1', 'value2'
	set @i=@i+1
end

--Kayit sayisini arttiriyoruz
declare @i int
set @i = 0
while @i < 8
begin
	insert into tbl_CompSample select * from tbl_CompSample
	set @i = @i + 1
end

--255.744 kayittan olusan bir calisma tablosu hazirladik
select count(*) from tbl_CompSample

--Sorgumuz su sekilde
--Sorguda Gender kolonu esitlik seklinde iken City kolonu esitlik degil seklinde kullanilmis
--	Bu yuzden Gender kolonunun selectivity'si daha az olmasına ragmen index'de bu kolonu basta kullanmak best practice'dir
select Col1, Col2 from tbl_CompSample
where Gender='M' and City between 34 and 50


--ilk olarak Gender, City seklinde bir nonclustered 
--index olusturup IO degerlerine bakiyoruz
create nonclustered index IX_1 on tbl_CompSample (Gender, City) include (Col1, Col2)

set statistics io on

select Col1, Col2 from tbl_CompSample
where Gender='M' and City between 34 and 50

--Bu index ile 389 logical read yapildi
--logical read degerini result kisminda gorebilirsiniz

--Simdi ayni index'i bu sefer City, Gender seklinde tanimlayalim
create nonclustered index IX_1 on tbl_CompSample (City, Gender) include (Col1, Col2)
with (drop_existing=ON)

select * from tbl_CompSample
where Gender='M' and City between 34 and 50

--Bu sekilde ise 754 IO yaptı.
--Cunku City daha secici olmasina ragmen esitlik degil seklinde
--	kullanildigi icin Gender, City daha iyi bir index'tir

--calisma tablosunu drop ediyoruz
drop table tbl_CompSample
Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


19 Mart 2013 Salı (Yarın) günü yapacağım webcast’in duyurusunu yapmak istiyorum.

SQL Server 2012 yenilikleri üzerine konuşacağımız webcast saat 10:00’da başlayacak.

Kayıt olmak için aşağıdaki linki kullanabilirsiniz.

Başlangıcı: 19 Mart 2013 Salı 10:00 
Saat dilimi: (GMT+02:00) 
Süre: 1 saat
Kayıt Linki : http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200178672&CR_EAC=300073606

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


18.03.2013 Pazartesi gunu MS Ankara ofisinde duzenlenecek SQL Server Onculeri etkinligine AlwaysOn sunumu ile katiliyorum olacagim.

Ankara'daki arkadaslar ile gorusmek uzere

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


 

[12.09.2013] Update : Soruları bu blog sayfasından yönetmek oldukça zor oluyor. Lütfen bundan sonraki sorularınız için turgaysahtiyan.com facebook sayfasını kullanınız.

Aralarda gözden kaçırmış olduğum sorular olabilir. Bunları da facebook sayfamda tekrar sorabilirsiniz.

 

Merhaba

Sizlerden mail ile oldukça fazla sayıda soru almaktayım. Bu soruların cevaplarının maillerde kalıp kaybolmasındansa bunlar için bir sayfa açarak herkesin bu cevaplardan faydalanmasının daha mantıklı olacağını düşündüm.

Bu yüzden artık sorularınızı mail ile değil buradan cevaplayacağım.

Makaleler ile ilgili sorularınızı ilgili makalenin altında sormaya devam edebilirsiniz. Onun haricindeki generic soruları ise buradan sorabilirsiniz.

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


As you know,statistics are used for row estimation during query plan generation phase. So they are really important for performance. If the “Auto Create Statistics” database option is On, for every column on where clause or join, statistics are automatically created by database engine.

[more]

These auto created statistics can be unused in the following days. So, how can we find these unused statistics?

As you know, if auto update statistics database option on, statistics are automatically updated if %20+500 row changed threshold is reached and related statistics are used. So first rule for automatic update operation is %20+500 row changes threshold (this thresholds are tracked in sysindexes.rowmodctr column), and second rule is related statistics must be used to be update.

Below script searches all statistics and find number of changes and last update time for all statistics. If the number of changes are higher than threshold but statistic is not updated, that means this statistic is not used since last update time.

use AdventureWorks2008
GO
select TableName, StatsName, auto_created, UpdatedRowCount, TableRowCount
      , case TableRowCount when 0 then 0 else UpdatedRowCount*1./TableRowCount end as UpdatedPercentage
      , StatsLastUpdatedTime 
from(
select OBJECT_NAME(id) as TableName
      ,s.name as StatsName
      ,s.auto_created
      ,rowmodctr as UpdatedRowCount
      ,(select SUM(row_count) from sys.dm_db_partition_stats where object_id=i.id and (index_id=0 or index_id=1)) as TableRowCount
      ,STATS_DATE(i.id,i.indid) as StatsLastUpdatedTime
from sysindexes i
left join sys.stats s on s.object_id=i.id and s.stats_id=i.indid
)xx
order by (case TableRowCount when 0 then 0 else UpdatedRowCount*1./TableRowCount end) desc

Sample result;

image

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


SQL Server 2012 ile beraber gelen güvenlik yeniliklerinden biri de windows group’lar için default schema atayabilme özelliğidir. Bugünkü makalemde bu konu üzerine konuşuyor olacağız.

[more]

SQL Server 2012’den önceki sürümlerde herhangi bir windows ya da domain group SQL Server üzerinde yetkilendirilirken default schema ataması yapılamıyordu. Dolayısıyla bu group’un içerisinde bulunan bir kullanıcı eğer dbo yetkisinde değil ise oluşturduğu objelerin scheması kendi adını alıyordu. Bu da yönetilebilirliği azaltan bir durumdu.

SQL Server 2012 ile beraber artık windows group’lara default schema atayabilmekteyiz. Dolayısıyla artık aynı grup vasıtasıyla yetkilendirilen 100’lerce login kendi schema’larını değil default schema olarak atanan schema’yı kullanabilecekler.

Şimdi bu dediklerimizi ufak bir örnek yaparak pekiştirelim. Örnekleri hem 2008 hem 2012 instance’ımda yapacağım ve aralarındaki farkı göstermeye çalışacağım.

İlk olarak aşağıdaki TSQL komutları vasıtasıyla WinGroup1 adındaki windows login’i için yeni bir login create ediyoruz ve daha sonra da bu login için deneme1 veritabanında yeni bir user create ediyoruz.

USE [master]
GO
CREATE LOGIN [TURGAYS03\WinGroup1] FROM WINDOWS WITH DEFAULT_DATABASE=[master]
GO
USE [deneme1]
GO
CREATE USER [TURGAYS03\WinGroup1] FOR LOGIN [TURGAYS03\WinGroup1]
GO

Farklılık bu noktadan sonra başlamakta. Aşağıdaki script ile WinGroup1 user’ına default schema ataması yapmak istiyorum. SQL Server 2012’de çalışan bu kod, SQL Server 2008’de bu özellik desteklenmediği için hata almakta.

USE [deneme1]
GO
CREATE SCHEMA [WinGroup1] AUTHORIZATION [TURGAYS03\WinGroup1]
GO
USE [deneme1]
GO
ALTER USER [TURGAYS03\WinGroup1] WITH DEFAULT_SCHEMA=[WinGroup1]
GO

SQL Server 2008’de alınan hata aşağıdaki gibi.

Msg 15259, Level 16, State 2, Line 1
The DEFAULT_SCHEMA clause cannot be used with a Windows group or with principals mapped to certificates or asymmetric keys.

Aynı işlemi SSMS üzerinden yaparsak ;

image

Default schema atama işlemini SQL Server 2008’de yapamadığımızı gördük. Peki bu durum tam olarak ne gibi bir sıkıntı oluşturmakta.

Aynı user’a table create etme hakkı verip daha sonra bu grubun içerisinde olan bir user ile SSMS’I açıp tablo create ediyoruz.

use [deneme1]
GO
GRANT CREATE TABLE TO [TURGAYS03\WinGroup1]
GO

--Aşağıdaki işlem WinGroup1 windows grubunun içinde bulunan
--WinUser1 kullanıcı ile SSMS açılıp yapılmıştır.
use [deneme1]
GO
create table denemetbl(a int)

Bu işlemi SQL Server 2012’de yaptığımızda gruba hangi schemayı default olarak atadıysak yeni create ettiğimiz table’ın scheması’da bu schema oluyor.

Fakat aynı işlemi SQL Server 2008’de yaptığımızda, default schema ataması yapamadığımızdan dolayı yeni create edilen user’ın schema’sı kullanıcı adı (WinUser1) olmakta.

Grubun içinde 100’lerce kullanıcı olduğunu düşünün. Bu durumda her kullanıcı için ayrı schema oluşturulacağı için yönetilebilirlik oldukça azalacaktır. Ayrıca kullanıcının silinmesi gerekliliğinde de schema değişiklikleri yapılması gerekmekte ki bu durum çoğu durumda oldukça sıkıntı çıkarmakta.

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


Küresel çapta faaliyet gösteren en büyük SQL Server topluluğu olan PASS'in tam gün ücretsiz etkinliği SQLSaturday'in 182.si 1 Aralık 2012 tarihinde istanbul’da yapılıyor. Türkiye’de ikinci defa gerçekleştirilecek SQLSaturday etkinliğinde katılımcılara ileri seviye teknik içeriklerden oluşturulan 6 workshop oturumu sunulacaktır.

Katılımcılar SQL Server MVP ve konusunda uzman Microsoft çalışanları tarafından hazırlanan SQL Server odaklı workshop'lara katılma şansı yakalarken aynı zamanda diğer katılımcılar ve sponsorlar ile iletişime geçerek iş ağlarını geliştirme firsatı yakalayacaktır.

Kayıtlar 300 kişi ile sınırlandırılmıştır. Kayıt olmak için acele edin!

[more]

Not: Kayıt esnasında şirket uzantılı mail adresi kullanılması gerekmektedir. Kişisel mail adresi kullanılarak yapılan kayıtlar geçerli sayılmayacaktır.

Tarih: 01 Aralık 2012, Cumartesi / 09:30 - 17:00

Yer: Bahçeşehir Üniversitesi - B Konferans Salonu, Çırağan Cad. No:4 Beşiktaş/İstanbul

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


SQL Server 2012 SP1’i aşağıdaki adresten yükleyebilirsiniz.

http://www.microsoft.com/en-us/download/details.aspx?id=35575

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


Daha önce şu makalemde bir instance’da bulunan tüm veritabanlarının boyutlarını sp_msforeachdb sistem prosedürünü kullanarak nasıl raporlayabileceğimizi görmüştük.

[more]

Bir müşterimde aynı raporu cursor kullanarak alma ihtiyacımız doğdu. Raporun cursor versiyonlu halini aşağıda paylaşıyorum.

create table #tmp1 (DBName varchar(100),reservedpages float,usedpages float,pages float)
declare @cmd varchar(max)='',
		@DBname sysname
		
select DB_NAME (dbid) as DBName, Cast(sum(Size)/128. as numeric(18,2)) as FileSize_MB
into #tmp2	   
from sys.sysaltfiles 
where dbid > 4  and dbid<1000 and groupid <> 0
group by DB_NAME (dbid)

declare curx cursor
for
	select name from sys.databases
	open curx
	fetch next from curx into @DBname
	while (@@FETCH_STATUS = 0) begin
		set @cmd='use '+ @DBname +'
			insert #tmp1
			select '''+@DBname+''',sum(a.total_pages) as reservedpages,  
				sum(a.used_pages) as usedpages,  
				sum(  
				CASE  
					When it.internal_type IN (202,204,211,212,213,214,215,216) Then 0  
					When a.type <> 1 Then a.used_pages  
					When p.index_id < 2 Then a.data_pages  
					Else 0  
				END ) as pages
			from sys.partitions p join sys.allocation_units a on p.partition_id = a.container_id  
			left join sys.internal_tables it on p.object_id = it.object_id'  
		exec (@cmd)
		fetch next from curx into @DBname
	end

close curx
deallocate curx

select  
	t1.DBName,
	t2.FileSize_MB,
	Cast(Round(t1.reservedpages * 8192 / 1024. /1024.,2) as Numeric(18,2)) as reserved_size_MB, 
	Cast(Round(t1.pages * 8192 / 1024. / 1024.,2) as Numeric(18,2)) as data_size_MB,
	Cast(Round((t1.usedpages - t1.pages) * 8192 / 1024. / 1024.,2) as Numeric(18,2)) as index_size_MB,
	Cast(Round(t1.usedpages * 8192 / 1024. / 1024.,2) as Numeric(18,2)) as total_used_size_MB,
	Cast(Round((t1.reservedpages - t1.usedpages) * 8192 / 1024. / 1024.,2) as Numeric(18,2)) as unused_from_reserved_size_MB,
	t2.FileSize_MB - Cast(Round(t1.reservedpages * 8192 / 1024. /1024.,2) as Numeric(18,2)) as unused_from_file_size_MB
from #tmp1 t1
join #tmp2 t2 on t2.DBName=t1.DBName
order by t1.DBName

drop table #tmp1
drop table #tmp2

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


10 Ekim 2012 Çarşamba günü yapacağım webcast’in duyurusunu yapmak istiyorum.

SQL Server 2012 yenilikleri üzerine konuşacağımız webcast saat 10:00’da başlayacak.

Kayıt olmak için aşağıdaki linki kullanabilirsiniz.

Başlangıcı: 10 Ekim 2012 Çarşamba 10:00
Saat dilimi: (GMT+02:00)
Süre: 1 saat 30 dakika
Kayıt Linki : https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032527841&Culture=TR-TR&community=0

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


SQL Server Error Log best practice’lerini anlattığım şu makalemde Error Log sayısının öneminden de bahsetmiştik. Bugün göstereceğim script ile error log dosya sayısını TSQL ile nasıl sorgulayabileceğimize bakıyor olacağız.

[more]

SQL Server error log sayısını sorgulamak için aşağıdaki script’i kullanabilirsiniz.

declare @NumErrorLogs int

exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'NumErrorLogs', 
	@NumErrorLogs OUTPUT

select @NumErrorLogs

Bu script’i registered servers özelliğini kullanarak tüm sunucular üzerinde tek seferde çalıştırarak best practice’e uymayan sunucularınızı kolayca bulabilirsiniz.

Bir diğer seçenek ise central management servers ile beraber policy based management kullanmak olabilir.

Son olarak SQL Server error log’lar ile ilgili aşağıdaki 2 makalemi okumanızı tavside ederek yazımı noktalıyorum.

SQL Server Logları’nı Okumak İçin Özelleştirilmiş Log Arama Stored Precedure ü

SQL Server Başarılı Backupların Error Log’a Yazılmasını Engellemek

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


SQL Server’da bulunan veritabanları üzerinde yapılan auto growth işlemlerinin ne kadar sürdüğünü ve ne zaman yapıldığını sorgulamak için default trace’i kullanabilirsiniz.

[more]

İlk olarak default trace sonuçlarının hangi file’da tutulduğuna bakıyoruz.

select * from sys.traces
where is_default=1

Yukarıdaki sorgu sonucu gelen result set’te bulunan path bilgisini fn_trace_gettable fonksiyonuna parametre olarak göndererek default trace’i sorguluyoruz.

SELECT databaseid, filename, SUM(IntegerData*8) AS Growth_KB, Duration, StartTime, Endtime
FROM ::fn_trace_gettable('C:\Program Files\Microsoft SQL Server\MSSQL11.SS2012\MSSQL\Log\log_31.trc', default)
WHERE EventClass = 92 OR EventClass = 93
GROUP BY databaseid, filename, IntegerData, Duration, StartTime, Endtime
ORDER BY StartTime

image

Sorgu sonucunda benim instance’imda gerçekleşen auto growth işlemlerini sorgulamış olduk.

Default trace bildiğiniz gibi belirli boyutta kayıt tutmakta. O yüzden auto growth işlem loglarını kaybetmemek adına ya default trace sonuçlarını belirli periyotlarda başka bir log tablosuna yazmamız ya da auto growth’ları monitor etmek için ayrı bir trace başlatmamız daha sağlıklı bir yaklaşım olacaktır.

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


As you all know, on of the most important best practices is all data files of TempDB should be same size.

If you have 4 core processor on your box, then best practice is create Tempdb with 4 data files, and set the initial size for all of them. (let’s say 1 GB)

After that what if Tempdb needs to grow? At this time one of Tempdb data file will be grow and all data files’ size are not identical anymore.

There’s a trace flag for this purpose. With T1117 trace flag, you can keep all data files’ size same after auto growth. I mean all data files growth together if your database needs to grow

Let me give an example. Assume that your TempDB has 4 data files and each data file has 1GB initial size and 256Mb auto growth value. If Tempdb needs to grow, not only one data file grow, all data files grow together, so you can keep them same size.

One last word, this trace flag is instance wide. So every databases in this instance may affected by this behavior.

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


Biraz uzun bir makale başlığı oldu değil mi? Ama bir o kadar da ilginç. Peki ne demeye çalışıyorum?

[more]

Kısa bir “recovery model” bilgi tazelemesi yaparak konuya gireyim.

Bildiğiniz gibi SQL Server’da Full, Simple ve BulkLogged olmak üzere 3 adet recovery model bulunmakta. Simple recovery model’de commit edilmiş transaction’lar checkpoint’ten sonra otomatik olarak truncate edilirken Full recovery model’de commit edilmiş transaction’ların truncate edilebilmesi için log backup alınması gerekmekte.

Peki Full Recovery Model, Simple Recovery Model gibi davranabilir mi? Yani Full Recovery Model’de transaction log backup almadan transaction’ların otomatik olarak truncate olması mümkün mü?

Makale başlığına bakmadan yukarıdaki soruyu okusaydınız büyük ihtimal cevabınız “hayır” olacaktı. Smile Ama evet böyle bir şey mümkün.

Full Recovery Model’e sahip database’in eğer full backup’ı hiç alınmadı ise bu veritabanı recovery model’i simple gibi davranmakta ve commit edilmiş transaction’lar checkpoint’ten sonra silinmekte.

İlginç değil mi?

Bir örnek vererek konuyu pekiştirelim. Örneğimde full recovery model’e sahip bir veritabanı create edeceğim ve insert’ten önceki ve sonraki log boyutlarına ve doluluk oranlarına bakacağım. Bu şekilde log’un otomatik olarak truncate edilip edilmediğini görmüş olacağım.

Önce bir çalışma DB’si create edip Recovery Model’ini Full olarak set ediyorum.

CREATE DATABASE FullRecDB ON PRIMARY (
    NAME = FullRecDB_data,
    FILENAME = N'C:\SQLData\FullRecDB_data.mdf')
LOG ON (
    NAME = 'FullRecDB_log',
    FILENAME = N'C:\SQLData\FullRecDB_log.ldf',
    SIZE = 50MB);
GO

USE [master]
GO
ALTER DATABASE [FullRecDB] SET RECOVERY FULL WITH NO_WAIT
GO

Şu an ki log doluluk oranı bakıyorum.

dbcc sqlperf(logspace)
go

Daha herhangi bir işlem yapmadığım için log doluluk oranı %1 in altında.

Full1

Şimdi bir çalışma tablosu create ediyorum ve daha sonra bir transaction başlatıp bu tabloya 8000 adet veri insert ediyorum.

use FullRecDB
GO
create table abc(a char(4000))
go

begin tran
GO
insert abc select 'a'
go 8000

Başka bir session’dan log doluluk oranına tekrar bakıyorum

dbcc sqlperf(logspace)
go

ve beklediğim gibi log'un kullanımı %80'ler seviyesinde

Full2

Şimdi açtığım transaction’ı commit edip checkpoint gönderiyorum ve sonrasında log doluluk oranına bir daha bakıyorum.

commit tran

checkpoint

dbcc sqlperf(logspace)
go

Normalde recovery model’im Full olduğu ve log backup almadığım için log doluluk oranımın gene %80’ler civarında gelmesini bekliyordum. Ama hiç full backup almadığım için database’im simple recovery model gibi davranıyor ve commit edilmiş transaction’ları siliyor. Bu yüzden log’un doluluk oranının düşmüş olduğunu görüyorum.

Full3

Aynı işlemleri en başta full backup alarak deneseydim log truncate olmayacaktı. Denemesi bedava Smile

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


You can find the free ebooks below.

clip_image002  clip_image003  clip_image004 

clip_image005  clip_image007  clip_image008

clip_image009  clip_image010  Moving to Visual Studio 2010

Programming Windows Phone 7

Enjoy Smile

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


Policy Based Management and Central Management Server feature can be used together to monitor some best practices over all SQL Server environment.

[more]

Today we are going to talk about how can we use policy based management to monitor Last Successful DBCC CheckDB date for all databases.

Basically we will use DBCC DBINFO() command to check last successful DBCC CheckDB date. In the result set, we will use the value of “dbi_dbcclastknowngood” field.

Here is the script which is used for condition;

ExecuteSql('Numeric', '
CREATE TABLE #tmp
	(ParentObject varchar(1000) NULL,Object varchar(1000) NULL,Field varchar(1000) NULL,Value varchar(1000) NULL)
insert into #tmp
EXEC (''DBCC DBINFO() WITH TABLERESULTS'')
select cast(value as datetime) from #tmp where field=''dbi_dbcclastknowngood''
drop table #tmp
')

Condition;

pbm1

and the policy;

pbm2

and a sample evaluation report for this policy;

pbm3

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


12 Eylül 2012 Çarşamba günü yapacağım webcast’in duyurusunu yapmak istiyorum.

SQL Server 2012 ile beraber gelen yeni High Availability çözümü olan AlwaysOn üzerine konuşacağımız bu webcast 10:00’da başlayacak.

Kayıt olmak için aşağıdaki linki kullanabilirsiniz.

Başlangıcı: 12 Eylül 2012 Çarşamba 10:00
Saat dilimi: (GMT+02:00)
Süre: 1 saat 30 dakika
Kayıt Linki : https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032527839&Culture=TR-TR&community=0

Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan


Bildiğiniz gibi “Alter Database” komutu, veritabanının recovery model, collation gibi veritabanı özelliklerini değiştirmek için kullanılır. SQL Server 2012 sürümünden önce veritabanı adının verilerek yapılması gereken bu işlemin örnek kodu aşağıdaki gibiydi;

alter database deneme set recovery simple

SQL Server 2012 ile beraber artık veritabanı adını belirtmemize gerek kalmıyor. “Current” keyword’ü ile o anda aktif olan veritabanı üzerinde Alter Database komutunu çalıştırabiliyoruz.

Örneğin aşağıdaki komut “deneme” veritabanının recovery model’ini simple yapmak için kullanılabilir.

use deneme
go

alter database current set recovery simple
Not : Blog haricinde, faydali gördügüm yazilari ve linkleri twitter adresimden paylasiyorum. Beni twitter'da takip etmek için : twitter.com/turgaysahtiyan