8 Aralık 2015 Salı

Bir Restore neden uzun sürer?

Merhabalar,

Bu aralar işler biraz yoğunlaştı, o nedenle bir şeyler paylaşmaya ara vermek durumunda kaldım. Yine de boşa çıkmış değilim; ama ne kadar ara verdiğimi görünce dayanamadım, daha dün yaşadığım bir olayı sizlerle de paylaşmak istedim.

Dün bir ortamda bazı veritabanlarını Restore etmem gerekti, kritik bir test durumu söz konusu olduğu için işlemi özellikle benim yapmam gerekti. Birkaç veritabanını Restore ettikten sonra, bazı veritabanlarının Restore işleminin ilginç bir şekilde duraksadığını, geciktiğini gözlemledim. Kuşkulandım ve ilk etapta sys.dm_exec_requests DMV'sini kullanarak işlemleri inceledim, birkaç Restore işleminin "percent_complete" alanındaki değer 100 idi, ama yine de işlemler bir türlü tamamlanmıyordu. Belki, herhangi bir garip nedenden dolayı SQL Server Management Studio'nun (SSMS) azizliklerinden biri olabilir diye düşündüm, SSMS'i kapattım açtım, sorun yine devam ediyordu. Sonra SQL Server Database Engine Service'ini kapatıp açtım, sonra sunucuyu komple kapattım açtım (test sunucusu) ve sorunun yine devam ettiğini gözlemledim.

En klasik sorun çözme yöntemlerinden olan kapat aç da işe yaramayınca artık daha derinlemesine bir araştırma şart olmuştu. Bunun için öncelikle 3004 ve 3605 Trace Flag'lerini aşağıdaki komut ile etkinleştirdim.

DBCC TRACEON (3004, 3605, -1)

Bu Trace Flag'ler ile Restore işleminin daha fazla kayıt üretmesini ve bu kayıtların da Error Log'a yazılmasını sağlamış oldum.

Ardından Error Log'ta aşağıdaki gibi kayıtlar gördüm:

SQL Server Error Log

Yukarıdaki ekran görüntüsünden de görüldüğü gibi bekleme anı Transaction Log dosyasının içerisinin sıfırlarla doldurulma anı. Bu anı Performance Monitor kullanarak ilgili sayaçlarla da izledim. Ayrıca Restore komutunu Script ile çalıştırdığım için aşağıdaki mesajı da görebildim ve not ettim:

Processed 857872 pages for database 'veritabanı_adı', file 'dosya_adı' on file 1.
Processed 2 pages for database 'veritabanı_adı', file 'dosya_adı_log' on file 1.

RESTORE DATABASE successfully processed 857874 pages in 528.709 seconds (12.676 MB/sec).

İşlem 529 saniyede ve saniyede sadece 12,6MB veri işleyerek tamamlanabilmişti. Bu gerçekten çok düşük bir değer, hele ki bu sunucudaki disklerden beklenen performans ile karşılaştırıldığında...

Aynı testi halihazırda üretim ortamında çalışan bir makinede denedim ve sonuç aşağıdaki gibi oldu:

Processed 857872 pages for database 'veritabanı_adı', file 'dosya_adı' on file 1.
Processed 2 pages for database 'veritabanı_adı', file 'dosya_adı_log' on file 1.

RESTORE DATABASE successfully processed 857874 pages in 48.744 seconds (137.496 MB/sec).

Gördüğünüz gibi işlenen sayfa sayısı aynı (857874), fakat üretim ortamındaki sunucuda aynı işlem 48,7 saniyede tamamlandı ve saniyede 137,5MB veri işleyerek. Bununla birlikte, bu işlemi üretim ortamındaki sunucuda da Performance Monitor ile izlemiştim ve veri yazma kapasitesi test sunucusundakine göre 6 kat daha hızlıydı.

Anlayacağınız, bu çalışmayla veritabanlarını Restore ederken aslında disk performans testi de yapmış olduk. Restore işlemlerinizi yaparken bir gariplik görürseniz görmezden gelmeyin, geçişten sonra başınız çok ağrıyabilir…

Kolay gelsin,
Ekrem Önsoy

27 Ekim 2015 Salı

SSMS'in azizliklerine dikkat!

Selam millet,

Bir ortamımda SQL Server 2008 R2 Instance'ı ve uyumluluk açısından da SQL Server Management Studio (SSMS)'nun ilgili versiyonu kullanılıyor.

Bu ortamdaki bir Index'i Covered Index yaparken hatırıma geldi, sizlerle de paylaşayım dedim. Seneler önce bir gün, çok yoğun Transaction olan bir ortamda çalışırken, yine bir Index'i değiştirirken büyük bir hata yapmıştım. SSMS bazen bu tür hataları yapmanıza çok yardımcı olabiliyor, konunun başlığı da buradan geliyor zaten.

Index'i Covered Index yapmak için SSMS'ten Index'in özelliklerine gittim, Included Columns bölümünden eklemek istediğim alanı ekledim ve sonra Script düğmesine tıklayıp Script'ini aldım ve sonuç aşağıdaki gibi oldu (tabii ki özel bilgileri gizledim): 

*********************************
USE []
GO
DROP INDEX [] WITH ( ONLINE = OFF )
GO
USE []
GO
CREATE NONCLUSTERED INDEX [] ON [dbo].[
(
[alan_adı1] ASC,
[alan_adı2] ASC,
)
INCLUDE ( [alan_adı3],
[alan_adı4]) WITH (STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

GO
*********************************

Özellikle yoğun ortamlar için bu çok tehlikeli bir kod örneği. Ben vaktinde bu hatayı yaptım, yine yoğun ortamlarda çalışan arkadaşlarım yapmasın. Eğer bu kodu çok yoğun Transaction'ların olduğu bir ortamda çalıştırırsanız, önce tablonuzu Index'siz bırakmış oluyorsunuz, ardından çok yoğun Blocking'ler oluşabiliyor, Index, IO ve tabii Cache masraflarınız dehşet şekilde artabiliyor ve bu yoğunlukta yeni Index'i öyle çabucak oluşturamıyorsunuz. Yığılan işlemlerin tamamlanmasını beklemek zorunda kalıyorsunuz. O gün nasıl kızardığımı ve zor durumda kaldığımı unutamam.

Tabii ki SSMS'i geliştirenler, kendilerini de zamanla geliştiriyorlar belli ki. Örneğin SQL Server 2014'ün SSMS'inde aynı tablo için aynı Included Column'ı eklediğinized ve Script'ini oluşturduğunuzda aşağıdaki gibi, yani olması gerektiği gibi bir kod oluşuyor:

*********************************
USE []
GO
CREATE NONCLUSTERED INDEX [] ON [dbo].[
(
[alan_adı1] ASC,
[alan_adı2] ASC,
)
INCLUDE ( [alan_adı3],
[alan_adı4]) WITH (STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = ON, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

GO
*********************************

Eğer Enterprise Edition kullanıyorsanız ONLINE parametresini de ON yapmalısınız. Eğer TempDB veritabanınız performanslı bir diskte ise, SORT_IN_TEMPDB parametresini de ON yapmalısınız. Böylece kritik Production veritabanınızda bu Index işlemiyle oluşacak olan yükü en aza indirgemiş olursunuz. Bununla birlikte, daha daha performans için Index'leri farklı bir diskteki farklı bir FileGroup'ta da tutabilirsiniz.

Peki DROP_EXISTING'in nasıl bu kadar büyük bir fark yaratabiliyor? Arkadaşım Turgay Sahtiyan zaten bu konuda bir makale yazmış, ben de aynı şeyleri tekrar yazmayayım.

SSMS'in azizlikleri sadece bununla kalmıyor. Hangi versiyondu çok çok emin değilim, ama muhtemelen SQL Server 2005'in SSMS'iydi, bir veritabanının özelliklerinde, bir dosyanın özelliklerini değiştirdiğinizde Shrink işlemi de yapıyordu. Bunu, o işlemi arayüzde yapmayıp Script'ini çıkarttığınızda görebiliyordunuz.

Yine başka bir Bug, ki bu son versiyonlarda da vardı, örneğin Log Shipping kurarken siz zaman olarak örneğin Log dosyalarımı sadece 3 gün tut olarak seçiyorsunuz arayüzde, fakat sonra aynı ekranı açtığınızda bir bakıyorsunuz 3 saat olarak kaydetmiş… Bu konuda bir makalem de vardı da, bulamadım.

Örneğin hala piyasadaki birçok yazılımcı, çok deneyimliler bile, bir tabloya bir alan ekleyecekleri zaman SSMS'teki Designer'ı kullanıyorlar. Bazı işlemlerde SSMS ilgili tabloyu tamamen siliyor ve tekrar oluşturuyor. Böyle bir şeyin Production ortamınızda olmasını gerçekten ister misiniz?

Bu yazımdan anlamanızı istediğim şey, işlemleri SSMS arayüzünden yaptıktan sonra hemen OK düğmesine basıp çalıştırmayın. Özellikle de kritik ortamlarda bunu sakın yapmayın. SSMS'in her versiyonda davranış değişiklikleri olabileceğinin bilincinde olun. Yapacağınız işlemin önce Script'ini çıkartın, mümkünse doğrudan ve sadece Script'i çalıştırın. T-SQL öğrenin, mümkün olan her yerde T-SQL ile çalışmayı alışkanlık haline getirin. Elbette Extended Event oluştururken arayüz kullanın veya benzer pratik durumlarda, fakat kritik işlemler için tetikte olmakta fayda var.

Kolay gelsin,
Ekrem Önsoy

22 Ekim 2015 Perşembe

HATA: The target principal name is incorrect. Cannot generate SSPI context. (Microsoft SQL Server)

HATA:
The target principal name is incorrect. Cannot generate SSPI context. (Microsoft SQL Server)

Error Log dosyasında da şu hata görünüyordu:
The SQL Server Network Interface library could not register the Service Principal Name (SPN) [ MSSQLSvc/..local ] for the SQL Server service. Windows return code: 0x21c7, state: 15. Failure to register a SPN might cause integrated authentication to use NTLM instead of Kerberos. This is an informational message. Further action is only required if Kerberos authentication is required by authentication policies and if the SPN has not been manually registered.

AÇIKLAMA:
Ortamlarımızdan birinde, 3 sunucudan oluşan AlwaysOn Availability Group kurulumu yapıyoruz bu günlerde. Kerberos yöntemini kullanmak için SPN kayıtlarımızı oluşturmuş, 3 sunucuda da SQL Server servisi olarak aynı hesabın kullanılmasını sağlamıştık. Fakat daha sonra, standart oluşturarak SQL Server servisi için kullanılacak olan hesabı değiştirdik. Akabinde, sunucuların ikisine RDP yaparak, SSMS ile diğer bir tanesine bağlanırken bu hatayı almaya başladık. Bağlanma işlemini tam ters yönlü yaptığımızda, yani bağlanırken sorun yaşadığımız sunucudan diğer iki sunucuya yaptığımızda bir hata ile karşılaşmıyorduk.

Hata mesajında SSPI'ı ve SQL Server Error Log'unda yukarıdaki hatayı gördüğümde, sorunun SPN ile ilgili olduğunu anladım. Domain yöneticisi arkadaşımla oraya odaklandık.

ÇÖZÜM:
SPN kayıtlarını SQL Server servis hesabını değiştirmeden önce oluşturmuştuk. Domain yöneticisi arkadaşım iki sunucu ile ilgili kayıtları silip yeniden oluşturmuş, fakat bir sunucunun kaydını güncellemeyi atlamışız. Bu hata mesajını aldığımız sunucu da oydu. Eski SPN kaydını sildik ve yeni SPN kaydını yeni servis hesabını kullanarak oluşturduk, böylece sorun çözülmüş oldu. Artık Error Log'da da SQL Server servis açılışında SPN ile ilgili olması gerektiği gibi aşağıdaki kaydı görüyoruz:

The SQL Server Network Interface library successfully registered the Service Principal Name (SPN) [ MSSQLSvc/..local: ] for the SQL Server service.

Ekrem Önsoy

20 Ekim 2015 Salı

HATA: AlwaysOn AG'de MultiSubnetFailover parametresi kullanıldığında oluşan zaman aşımı sorunu

HATA:
Connection Timeout Expired.  The timeout period elapsed while attempting to consume the pre-login handshake acknowledgement.  This could be because the pre-login handshake failed or the server was unable to respond back in time.  The duration spent while attempting to connect to this server was - [Pre-Login] initialization=63121; handshake=42327;

"Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.  This may have occurred because all pooled connections were in use and max pool size was reached."

AÇIKLAMA:
AlwaysOn Availability Group SQL Listener'ınıza aşağıdaki gibi bir Connection String ile bağlanırken, yukarıdaki gibi hatalar alabilirsiniz.

Connection String örneği:
Data Source=tcp:, ; Initial Catalog=; User Id=; Password=; Connection Timeout=60; MultiSubnetFailover=True

ÇÖZÜM:
Ben bu hata ile Windows 7 işletim sistemlerinde karşılaştım. Test ortamımda an itibariyle diğer işletim sistemleri olmadığından deneyemedim, o yüzden onlarda da var mı, yok mu şu anda bilemiyorum.

Sorun, aşağıda paylaştığım Microsoft Knowledge Base'te de anlatıldığı gibi Tdx.sys isimli sürücünün, işlev bir TCP/IP elsıkışması ortasında çağrıldığında Closesocket() isimli işlevi başarıyla kontrol edememesinden kaynaklanıyormuş.

https://support.microsoft.com/en-us/kb/2870437

Eğer Windows 7 kullanıyorsanız ve burada izah ettiğim sorunu yaşıyorsanız, yukarıdaki KB'deki Hotfix'i indirip kurduktan sonra bu sorundan kurtulacaksınız.

Ekrem Önsoy

HATA: Invalid Urn filter on server level: filter must be empty, or server attribute must be equal with the true server name.

HATA:
Invalid Urn filter on server level: filter must be empty, or server attribute must be equal with the true server name.

AÇIKLAMA:
AlwaysOn Availability Group'unuzdaki bir Secondary Replica'yı Primary Replica'dan değil de, başka bir Secondary Replica'dan silmeye çalışırken bu hata mesajıyla karşılaşabilirsiniz.

Güncelleme (23.10.2015):
Bu hatanın daha genel bir hata mesajı olduğunu gördüm. Bu hatayı aldığınız zaman, işlem yapmak istediğiniz sunucuya SQL Listener adıyla değil, doğrudan o SQL Server Instance'ının adını kullanarak bağlanın, o zaman bu hatayı almazsınız.

ÇÖZÜM:
Secondary Replica'yı Primary Replica'ya bağlanarak oradan gruptan çıkarmayı deneyin.

Ekrem Önsoy

13 Ekim 2015 Salı

SQL Server Audit - Filtreleme

Selam millet,

En son SQL Server Auditing özelliğini SQL Server 2008 kullanılan bir ortamda etraflıca kullanmıştım, bugün tekrar böyle bir kurulum yaparken ve yenilikleri incelerken fark ettim ki SQL Server 2012 ile birlikte loglanacak verinin filtrelenebilmesi sağlanmış. Bu loglama, tam olarak veri log dosyasına yazılmadan önce yapılıyor.

Bu ayar, SSMS->Object Explorer->Security->Audits öğesinde ayarladığınız hedef dosyanın özelliklerindeki Filter bölümünden veya T-SQL ile ayarlanabiliyor.


Örneğin yukarıdaki örnekte özellikle 2 Login'e ait işlemlerin loglanmamasını istediğimi belirttim. Bu alanı WHERE'den sonra Predicate'leri tanımlıyoruz gibi düşünün.

İlgili sayfa olan https://msdn.microsoft.com/en-us/library/cc280525(v=sql.110).aspx adresinde bu konuda özet bir bilgi verilmiş ve şöyle denmiş:

"Optionally, on the Filter page, enter a predicate, or WHERE clause, to the server audit to specify additional options not available from the General page. Enclose the predicate in parentheses; for example: (object_name = 'EmployeesTable')."

Yani efendime söyleyeyim "İsterseniz Filter sayfasında bir Predicate veya WHERE cümleciği girebilir ve General sayfasında varolmayan bazı seçenekleri belirtebilirsiniz. Predicate'leri parantez içinde yazın, mesela (object_name = 'EmployeesTable') gibi." diyor.

Peki burada Predicate olarak kullanılabilecek alanlar nelerdir? Nereden bulacağız bu alanları? Aşağıda adresini paylaştığım dokümandaki alanları kullanabilirsiniz:


Kolay gelsin,
Ekrem Önsoy

19 Eylül 2015 Cumartesi

HATA: Server '' is not configured for RPC.

HATA: 
Server '' is not configured for RPC.

AÇIKLAMA:
X sunucunuzda Y sunucusu için kurduğunuz bir Linked Server'ı kullanarak X sunucunuzdan aşağıdaki kodu çalıştırdığınızda:

EXEC ('USE [master]') AT []

yukarıdaki gibi bir hata mesajıyla karşılaşabilirsiniz. Çalıştırdığınız komut başka herhangi bir komut da olabilirdi, yukarıda kullandığım "USE [master]" komutu sadece durumu anlatmak içindir.

RPC, Remote Procedure Call demektir ve SQL Server'a has bir özellik değil. Maksadı, uzaktaki sunucuda bir komut çalıştırmaktır.

ÇÖZÜM:
Linked Server yapılandırmanızı, aşağıdaki gibi, RPC'yi etkinleştirecek şekilde değiştirmeniz gerekiyor.

USE [master]
GO
EXEC master.dbo.sp_serveroption @server=N'', @optname=N'rpc out', @optvalue=N'true'
GO

Ekrem Önsoy

15 Eylül 2015 Salı

"msdb" veritabanını temiz tutmak

Selam millet,

Bazen gerçekten gerektiği için ve bazen neden alındığının bile belli olmadığı ve hatta bu yedeklerle ne zaman, kimin ve ne yapılacağının bile bilinmediği ortamlar gördüm. Transaction Log yedeklerinden bahsediyorum. Şirketin RPO ve RTO ihtiyaçları çerçevesinde ve özellikle kritik Production sistemler için Full ve Differential yedeklerin yanında sıklıkla Transaction Log yedeği alınması oldukça normaldir. Recovery Model'ın değişik modlarının ve Transaction Log dosyalarının nasıl yönetileceği tamamen çok geniş ve ayrı konular, ben bu kısa yazımda sizlere Transaction Log'ların sıklıkla alındığı ortamlarda "msdb" veritabanında düzenli temizlik yapılmadığında nasıl bir manzara ile karşılaşılabileceğine dair fikir vermek istiyorum.

Bugün Domain'de olmayan ve bu nedenle (ve tabii ki biraz da ilgili arkadaşımın ilgisizliği nedeniyle) ve benim bu sunucuya henüz kendi denetim ve izleme Script'lerimi kurmamam nedeniyle yukarıda bahsettiğim gibi bir rezaletle karşılaştım.

Efendim, görüntü aşağıdaki gibi:

"msdb" veritabanı yeterince temizlenmediğinde...

Gördüğünüz gibi yedekleme ile ilgili tüm tablolar almış başını gitmiş. Emin olun bundan çok daha beter ve rezil manzaralar da var, gördüm. Bununla birlikte, hazır bunu da görmüşken sizlerle de paylaşıp dikkatinizi çekeyim dedim.

Peki bu tablolar neden böyle dolar? Aslında yukarıda özetle değindiğim konuya tekrar değineyim. Genellikle Full veritabanı yedekleri günde bir kere veya haftada bir kere alınır (tabii ki duruma göre değişir!) ve keza Differential yedeklerin de günde en fazla 4 kere alındığını görmüşlüğüm var. Fakat Transaction Log yedekleri çok daha sıklıkla alınır, mesela her 5 dakikada bir sefer gibi (her 1 dakikada bir alındığını da gördüm!). Bu ne demek? Günde ortalama 288 adet Transaction Log yedek dosyası ve "msdb" sistem veritabanındaki ilgili yedek tablolarında 288 adet kayıt demek. İlgili SQL Server Instance'ındaki veritabanı sayısı, Transaction Log yedek alma sıklığı ve "msdb" veritabanının temizlenmeme süresi hesaba katıldığında, ilgili yedek tabloları gerçekten acayip fazla şişebilir.

Tek çekince tabii ki bu tabloların şişip yer kaplaması değil, genelde ve birçok ortamda bu tabloların tutulduğu "msdb" veritabanının dosyaları "C:" diskindedir. Çünkü DBA barındırmayan birçok şirkette SQL Server kurulumları "next, next" şeklinde yapılır ve Best Practice'ler takip edilmez. Hal böyle olunca, bu veritabanlarının büyümesi C: diskini tamamen doldurur, ki çoğu durumda Windows işletim sistemi ve hatta "tempdb" veritabanı da bu disktedir. Tabii ki bu durumda bir taraftan işletim sistemi teklemeye, "garip gurip" hatalar vermeye başlar, bir taraftan da kullanıcılar "tempdb"den "ilginç" hatalar almaya başlarlar.

Peki "msdb" veritabanınızı bu yedek tarihçesi kirliliğinden nasıl kurtaracaksınız? Aşağıdaki komut ile!

USE msdb;
GO
DECLARE @most_old_record_date DATETIME;

SELECT @most_old_record_date = DATEADD(DAY, - 365, GETDATE());

EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = @most_old_record_date;

Açıkçası yukarıda sizinle paylaştığım Script, benim asıl araç gereç kutumdakinin biraz değiştirilmiş versiyonu. Benim kendi kullandığım Script'lerin bir ana yapılandırma tablosu var, yukarıdaki -365 gibi tüm değerler o tablodan alınır. Size de tavsiyem, "msdb" veritabanında en azından 1 senelik kayıt eğer şartlar mümkünse bulundurun. Böylece örneğin geriye dönük olarak aldığınız yedeklerin boyutunun ne kadar büyüdüğünü tespit edebilirsiniz. Hoş bir istatistiki bilgi.

Şimdilik bu kadar! Esen kalın.
Ekrem Önsoy


An exception occurred while enqueueing a message in the target queue. Error: 15404, State: 19. Could not obtain information about Windows NT group/user 'DOMAIN\USERNAME', error code 0x5.

HATA:
An exception occurred while enqueueing a message in the target queue. Error: 15404, State: 19. Could not obtain information about Windows NT group/user 'DOMAIN\USERNAME', 
error code 0x5.


AÇIKLAMA:
Dün de bu hata ile karşılaşınca, hatırlayıp arşivime baktım ve bu hata ile 2010 senesinde de karşılaştığımı gördüm.

SQL Server Error Log'larında yukarıdaki gibi hata mesajları görüyordum. Domain kullanıcıları SQL Server'a giriş yapamıyordu ve hatta yeniden başlattığımızda SQL Server servisi bir Domain Account'u kullandığı için başlatılamıyordu.

ÇÖZÜM:
Bu sefer bu hatanın nedeni bu sorunu yaşadığım sunucu üstündeki Time servisinin senkron olmamasından kaynaklanıyordu. Bu servisi tekrar senkron hale getirince sorun çözüldü.

Kolay gelsin!
Ekrem Önsoy

28 Ağustos 2015 Cuma

Kitap incelemesi: SQL Server 2014 Query Tuning & Optimization, yazar Benjamin Nevarez

Selam millet,

Aslında amazon.com'dan geçen sene sonunda satın aldığım bu kitabı, nihayet bugün bitirebildim.

Kitapta Benjamin, temel olarak şu konulardan bahsetmiş:
- Sorgu iyileştirmeye giriş,
- Sorgularla ilgili sorunların çözümü,
- Sorgu iyileştirici (Query Optimizer),
- Sorgu operatörleri,
- Index'ler,
- İstatistikler,
- In-Memory OLTP,
- Plan Cache,
- Veri ambarları,
- Sorgu işlemcisinin (Query Processor) sınırlamaları ve Hint'ler.

Kusura bakmayın biraz İngilizce/Türkçe kırması, tarzanca gibi oldu; ama bazı terimleri de çevirmeye çalışmak zor ve anlaşılmaz olabiliyor. Bununla birlikte bu terimlere zaten aşina değilseniz, bu konularla da ilgilenmiyorsunuzdur diye tahmin ediyorum, o yüzden bu noktaya çok da takılmayacağım.

Kitabın ilk bölümünde nasıl daha iyi "Execution Plan" üretilebilecek kodlar yazılabileceğinden, "Query Processor"un iç dinamiklerinden, performanslı çalışmayan sorgular için hangi SQL Server Tool'larının kullanılabileceğinden, "Execution Plan"ların nasıl okunabileceğinden bahsediliyor.

İkinci bölümde, sorgularımızın IO ve CPU gibi sistem kaynaklarını nasıl kullandığını öğrenmemize yardımcı olacak bazı teknikler gösteriliyor. Temel olarak "Extended Event"lerden ve "Data Collector"den, masraflı sorguları takip etmemize yardımcı olacak bazı "DMV" ve "DMF"lerden ve "SQL Trace"ten bahsediliyor.

Üçüncü bölümde Query Optimizer'ın nasıl çalıştığından, SQL Server'da çalıştırılmak üzere girdiğimiz bir SQL cümleciğinden nasıl bir "Execution Plan" oluştuğuna kadar, "parsing", "binding", "simplification", "trivial plan" ve "full optimization" safhalarından nasıl geçtiği ve "Query Optimizer" mimarisinin önemli parçaları anlatılıyor.

Dördüncü bölümde "Execution Plan"lardaki sık kullanılan operatörlerden bahsediliyor. Algoritmalar, karşılaştırmalı masraflar ve sık kullanılan operatörlerin hangi durumlarda ve neden kullanıldığından bahsediliyor. "Execution Engine" tarafından sıralama (Sorting) ve Hashing kavramlarının nasıl kullanıldığına, verileri birleştirme (Join) ve kümeleme (Aggregation) algoritmalarına da değinilmiş.

Beşinci bölüm Index'lere ayrılmış. Temel olarak B-Tree Index'lerinden bahsedilmiş, bu Index'lerin ne zaman ve nasıl kullanıldıkları ve Index'lerin parçalanması (fragmentation) konusu anlatışmış. Bunların yanında "Database Tuning Advisor" ve Index'lerle ilgili DMV'lerden de bahsedilmiş.

Altıncı bölümde İstatistikler'in SQL Server tarafından nasıl faydalanıldığı, istatistiklerin elementleri tanıtılıyor ve açıklanıyor. Ayrıca burada da Beşinci bölümdeki gibi İstatistiklerin bakımından bahsedilmiş.

Yedinci bölüm SQL Server 2014 ile birlikte gelen In-Memory OLTP (Hekaton) özelliğinin tanıtımına ayrılmış. Hatırlarsanız Benjamin Nevarez, geçen seneki Microsoft Türkiye ofisinde sevgili arkadaşım Yiğit Aktan'ın düzenlediği organizasyonla SQLSaturday'e de katılmıştı ve SQLSaturday öncesindeki Cuma günü de bir Precon oturumu yapmıştı. Bu Precon'da da, ertesi günkü SQLSaturday etkinliğinde de yine Hekaton'dan bahsetmişti.

Sekizinci bölüm "Plan Cache"e ayrılmış. Evet, her konu çok önemli, fakat ben Plan Cache'in özellikle kariyerinde belli bir noktaya gelmiş kişiler tarafından çok iyi bilinmesi gerektiğini düşünüyorum. SQL Server 2005 ile gelen DMV'ler sayesinde Plan Cache'teki birçok bilgiye çok daha ayrıntılı ulaşabiliyoruz. Özellikle performans sorunlarının çözümünde, Plan Cache'teki verilerden bu DMV'lerle faydalanabilmek çok önemli. Benjamin de bu bölümde sorgularımızın planlarının nasıl Plan Cache'te tutunup birden fazla kez kullanılabileceğinden ve diğer ilgili ayrıntılardan bahsetmiş.

Dokuzuncu çok kısa bir şekilde veriambarlarına değinmiş. Aslında burada temel olarak anlattığı şey OLTP ile OLAP sistemler arasındaki farkı vurgulamak ve SQL Server 2012 ile birlikte gelen Columnstore Index'lere değinmek olmuş. Ufaktan Fact tablolara, Star Join'lere, Batch işlem modundan da bahsetmiş.

Onuncu ve son bölümde ise SQL Server'daki bazı sınırlamalara dikkat çekmiş. Örneğin SQL Server'ın ender de olsa iyi Execution Plan'lar oluşturamadığından ve bu durumlarda neler yapılabileceğinden bahsedilmiş.

Genel olarak kitabı beğendim ben, alıp okumanızı tavsiye ederim.

Ekrem Önsoy

21 Ağustos 2015 Cuma

Implicit Conversion neden "kaka"dır?

Selam arkadaşlar,

Şimdiye kadar bu ve buna benzer çok sorunu çözdüm, ama şimdi bir vakit aralığı buldum ve istatistikleriyle birlikte güzel bir örnek olacağını düşündüğüm için bunu özellikle sizlerle paylaşmak istedim. Lütfen bu örneği küçük bir ders gibi görün ve dikkatlice inceleyin. T-SQL'ı işinde kullanıyor olanlarınız için, kariyerinizin geri kalanında da çok işinize yarayacaktır.

Öncelikle "Implicit Conversion" nedir, kısaca önce bunu tanımlayayım. Diyelim ki aşağıdaki gibi bir tablonuz var:

CREATE TABLE dbo.Gonderilenler(
GonderiNo BIGINT,
)

CREATE TABLE dbo.Gonderilecekler(
GonderiNo VARCHAR(50),
)

Ve aşağıdaki gibi bir Stored Procedure (SP)'ünüz var:

CREATE PROCEDURE dbo.GonderiSorgula
@GonderiNo DECIMAL(11,0)
AS
SET NOCOUNT ON;

SELECT … FROM dbo.Gonderilenler WHERE GonderiNo = @GonderiNo;
SELECT … FROM dbo.Gonderilecekler WHERE GonderiNo = @GonderiNo;

Burada dikkatinizi çekmek istediğim şey, Gonderilenler ve Gonderilecekler tablolarının ikisinde de GonderiNo adında bir alanın bulunması, fakat bu iki alan için farklı veritiplerinin kullanılması. Maalesef birçok ortamda, aynı maksatla kullanılan ve farklı tablolarda bulunan alanlar için yazılımcıların farklı veritiplerini kullandığını görebiliyoruz. Yazılımcılar bu konuda gerçekten çok dikkatsiz olabiliyorlar. Örneğin bir ortamımda, aynı amaçla kullanılan alan için, farklı onlarca tabloda, farklı veritipleri kullanıldığını gördüm. Bu sorunu düzeltmek de ayrı bir sorun, bundan da belki başka bir yazımda bahsederim.

Nerede kalmıştık efendim? Evet, Implicit Conversion nedir, nasıl oluştur? Eğer yukarıdaki dbo.GonderiSorgula isimli SP'yi çalıştırırsanız, @GonderiNo değişkeninin veritipi ile dbo.Gonderilecekler tablosundaki GonderiNo alanının veritipleri uyuşmayacağı için nur gibi Implicit Conversion sorununuz olacaktır. SQL Server kendi içerisinde Numeric veritipi olan DECIMAL'ı, VARCHAR'a çevirecektir (Implicit Conversion tam olarak budur) ve bu nedenle de dbo.Gonderilecekler.GonderiNo alanı için güzel bir Index de olsa bu Index'ten faydalanılamayacak ve Index Scan işlemi yapılacaktır. Bu da, tüm tablonun taranması anlamına gelmektedir ve tablo ne kadar büyükse, o kadar büyük bir sorununuz var demektir. Implicit Conversion ile sadece IO değil, CPU sorunu da yaşarsınız. Örnekleri ve delilleriyle birlikte hepsini göstereceğim.

Bugün karşılaştığım sorunlu SP'nin bahsini ettiğim sorunlu kısmının önceki ve sonraki Execution Plan'larını da aşağıda görebilirsiniz. 

Aşağıdaki ekran görüntüsündeki INSERT operatörünün üstündeki üçgen içerisindeki ünlem işareti de Execution Planları incelerken her zaman dikkatinizi çekmeli. Eğer bu operatörün üstünde gelir ve beklerseniz bir Tooltip çıkacaktır (veya F4->Properties) ve orada size Implicit Conversion hakkında bir uyarı gösterilecektir. Tabii ki aşağıdaki senaryo için bu böyle. Başka senaryolarda ve operatörler için bu üçgen içerisindeki ünlem işareti "Spill to tempdb" gibi anlamlara da gelebilir.

SP'nin iyileştirmeden önceki Execution Plan'ı.

Aşağıda da, SP'nin yaptığım iyileştirme çalışmasından sonraki Execution Plan'ını görebilirsiniz.

SP'nin iyileştirmeden sonraki Execution Plan'ı.

Peki bu uyuşmazlığın, iyileştirme öncesindeki ve sonrasındaki etkisi nasıl? Lütfen aşağıda paylaştığım grafiğe bir gözatın. 

Bu Script kendi yazdığım bir Script. Bu Script sayesinde Cache'lenebilen sorguların ve nesnelerin eski istatistiklerine ve Execution Plan'larına ulaşabiliyorum. 
Grafiğin en üst kısmında, kırmızı ile işaretlediğim yerde SP'nin şu anki, yani iyileştirmeden sonraki masrafını göreceksiniz; alttaki kayıtlar ise, SP'nin iyileştirme öncesinde nasıl çalıştığına dair istatistikler. Gördüğünüz gibi kaynak kullanım masraflarındaki iyileşmeler binlerce kat.

Peki ne yaptımda Execution Plan Index Scan'i terk edip Index Seek yapmaya başladı? INSERT operatörünün üstündeki üçgen içerisindeki ünlem nereye gitti?

Benimki gibi gerçek hayat senaryolarında, her zaman her şey mükemmel olmuyor. Zaten öyle olsa, Implicit Conversion sorunu da yaşamıyor olurdum. Gerçek senaryomda, SP içerisinde sorgulanan tablonun ilgili alanının veritipini maalesef değiştiremiyorduk. Yani özellikle bir tablodaki ilgili alanın veritipi, diğer tablolarınkinden farklı kalmak durumundaydı. Nedenleri bana kalsın. Fakat benim her şeye rağmen bir çözüm üretmem gerekiyordu, çünkü ortada bir sorun vardı. Ben de en azından bu tablodaki ilgili alanın veritipini değiştirinceye kadar aşağıdaki çözümü ürettim. SP içerisine aşağıdaki gibi bir değişken tanımladım:

DECLARE @GonderiNo_str VARCHAR(50) = CAST(@GonderiNo AS VARCHAR(50));

Ve yukarıdaki senaryoya göre anlatacak olursak SP'min kodunu aşağıdaki gibi değiştirdim:

CREATE PROCEDURE dbo.GonderiSorgula
@GonderiNo DECIMAL(11,0)
AS
SET NOCOUNT ON;

DECLARE @GonderiNo_str VARCHAR(50) = CAST(@GonderiNo AS VARCHAR(50));

SELECT … FROM dbo.Gonderilenler WHERE GonderiNo = @GonderiNo;
SELECT … FROM dbo.Gonderilecekler WHERE GonderiNo = @GonderiNo_str;

Bu değişiklikten sonra bu SP'nin Execution Plan'ı yukarıda gösterdiğim gibi değişti.

SP'nin içerisindeki asıl @GonderiNo değişkeninin veritipi dbo.Gonderilenler tablosu için doğru olduğundan, bu için bu değişkeni kullanmaya devam ettim, ama dbo.email_gonderilenler tablosu için yukarıda tanımladığım yeni @GonderiNo_str veritipini kullandım. Böylece dbo.Gonderilecekler tablosu sorgulanırken Implicit Conversion yapılmamış ve varolan Index'ten en iyi şekilde faydalanılmış oldu. Evet, tek yaptığım buydu ve binlerce kat iyileşme elde ettim.

İyi kod yazmalar!

Ekrem Önsoy

16 Ağustos 2015 Pazar

Hata: Cannot enable compression for object...

HATA:
Msg 2786, Level 16, State 1, Procedure sp_estimate_data_compression_savings, Line 20
The data type of substitution parameter 3 does not match the expected type of the format specification.
Msg 7738, Level 16, State 2, Line 1
Cannot enable compression for object '#sample_tableDBA05385A6FF40F888204D05C7D56D2B_______________________________________________________________________000000063644'. Only SQL Server Enterprise Edition supports compression.


AÇIKLAMA:
Developer, Evaluation veya Enterprise Edition olmayan bir SQL Server Instance'ına bağlanıp, bir tablonuzu ROW veya PAGE veri sıkıştırma yöntemiyle sıkıştırırsanız ne kadar kazanım elde edeceğinizi hesaplamak için aşağıdaki komutu çalıştırırsanız bu hata ile karşılaşırsınız.

EXEC sp_estimate_data_compression_savings 
      @schema_name =  'schema_adi'  
   ,  @object_name =  'tablo_adi' 
   , @index_id =  NULL
   , @partition_number = NULL
   , @data_compression =  'PAGE' ;

ÇÖZÜM:
Örneğin eğer Express veya Standard Edition kullanıyorsanız bu hata ile karşılaşırsınız. Çünkü veri sıkıştırma özelliği sadece yukarıda, açıklama bölümünde belirttiğim Edition'lar için kullanılabilirdir. Maalesef Microsoft ne kazanım elde edebileceğimizi görmemiz için, hesaplama için kullanılabilecek bu SP'yi bile kullanmamıza izin vermiyor. Mantıklı olanı önce bu özellik ile ne elde edebileceğimizi görüp, ona göre Edition yükseltme işlemi yapıp yapmamaya karar vermek gibi görünüyor, yani bence de öyle, ama maalesef Microsoft böyle uygun görmemiş. Bu nedenle veri sıkıştırma ile nasıl bir kazanım elde edeceğinizi görmek için Evaluation, Developer veya Enterprise Edition kullanmanız gerekiyor.


Ekrem Önsoy

3 Ağustos 2015 Pazartesi

A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 0 - The semaphore timeout period has expired.)

HATA:
A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 0 - The semaphore timeout period has expired.)

AÇIKLAMA:
Uzaktaki bir sunucuya karşı, bir istemciden sorgu çalıştırdığınızda, sorgu çalışıyorken sunucu ile aranızdaki bağlantı koptuğunda böyle bir hata ile karşılaşırsınız.

Örneğin uzaktaki sunucuya VPN aracılığı ile bağlantı kurdunuz diyelim, internet bağlantınız gitti, o zaman bu hatayı alırsınız.

ÇÖZÜM:
İnternet bağlantınızın ve örneğin VPN bağlantınızın sağlıklı kurulu olduğundan emin olun.

29 Temmuz 2015 Çarşamba

SQL Server 2016: Dynamic Data Masking

Selam arkadaşlar,

SQL Server 2016 test ortamımda Dynamic Data Masking özelliğini test ettim, sonucu sizinle de paylaşmak istiyorum. Test için AdventureWorks2012.Person.PersonPhone tablosundaki PhoneNumber alanını kullandım. Dynamic Data Masking özelliğini kullanarak, aşağıdaki komutlarla NVARCHAR(25) veritipiyle oluşturulmuş PhoneNumber alanındaki değerlerin ortasındaki 3 karakteri XXX karakterleriyle maskeledim.

Maskelemeden önce verinin nasıl göründüğü

Maskeleme için kullandığım komutlar:

USE [AdventureWorks2012]
GO
ALTER TABLE Person.PersonPhone
ALTER COLUMN PhoneNumber ADD MASKED WITH (FUNCTION = 'partial(3,"-XXX-",4)');

Bu komut ile veriyi değiştirmiş olmuyoruz, sadece soyut olarak maskeliyoruz. db_owner ve sysadmin olmayan ve UNMASK yetkisi bulunmayan tüm kullanıcılar veriyi aşağıdaki gibi görüyor:

Maskelemeden sonra verinin yetkisiz bir kullanıcıya nasıl göründüğü

Eğer isteseydim telefon numaralarına dair hiçbir veriyi göstermezdim ve/veya istediğim sayıda "X" kullanırdım ve değerin kaç karakter olabileceği hakkında da yetkisiz kullanıcılara fikir vermeyebilirdim.

Aşağıdaki komut ile de maskeli bir alanın bu özelliğini kaldırabilirsiniz:

ALTER TABLE Person.PersonPhone ALTER COLUMN PhoneNumber DROP MASKED;

Dynamic Data Masking özelliğinin çalışabilmesi için, bu özelliğin kullanılacağı veritabanının Compatibility Level ayarının 130 (SQL Server 2016) yapılması gerekiyor. Örneğin Compatibility Level ayarı 90 (SQL Server 2005) olan bir veritabanı için bu özellik kullanılamıyor. 

Büyük bir olumsuzluk beklemesem de, performansa nasıl bir etkisi olacağını bilemiyorum; ama kullanımı gayet pratik, uygulama tarafında hiçbir değişiklik gerektirmiyor. Tek değişiklik yönetim tarafında, ilgili alanının yukarıda belirttiğim komut ile MASKED olarak tanımlanması ve ilgili / yetkili olacak kullanıcılara UNMASK yetkisinin verilmesi.

Bu özellik hakkında daha fazla bilgiye Books Online'dan ulaşabilirsiniz:

Kolay gelsin,


Ekrem Önsoy

24 Temmuz 2015 Cuma

SSMS yenileniyor! Artık daha yeni, daha dinamik, daha güncel!

Merhabalar,

Enterprise Manager'dan sonra SQL Server 2005 ile birlikte hayatımıza giren SQL Server Management Studio (SSMS) artık daha güncel ve dinamik olacak. Nasıl mı?

Şöyle efendim, şimdiye kadar SSMS'in yeni versiyonları hep SQL Server Database Engine'in yeni versiyonlarıyla birlikte, yani son versiyonlara göre bakarsak, iki senede bir çıkardı piyasaya. Özellikle Azure SQL Database gibi, 2 yıl gibi uzun aralıkları beklemeden sürekli yeni özelliklerin eklendiği dinamik bir servisin de devreye girmesiyle, SSMS'in de böyle dinamik bir şekilde güncellenmesi ihtiyacı hasıl oldu. Çünkü SSMS, Azure SQL Database servisinin yönetimi ve bu ortamda yapılacak geliştirme işleri için de kullanılacak en temel araç. Bu nedenle Azure SQL Database servisine yeni bir özellik eklendiğinde, bu özelliğin SSMS tarafından da desteklenmesi gerekiyor ve bu destek artık içinde bulunduğumuz bu süreçte 2 yıl gibi bir süre bekleyemez.

Bu kapsamda ben de Microsoft'un ilgili sayfasından SSMS'in bu yeni versiyonunu test makimene indirdim ve kurdum. SSMS'in bu versiyonu (SQL Server 2016 CTP 2.2 - 31,5MB), SSMS'in önceki versiyonlarıyla yanyana çalışabiliyor, yani bunu kurmadan önce eski versiyonları kaldırmanız şart değil. Ayrıca, SSMS'in bu versiyonu SQL Server 2005 versiyonundan itibaren tüm SQL Server servislerini de destekliyor.

SSMS SQL Server 2016 CTP 2.2
Yukarıdaki ekran görüntüsünden de görebileceğiniz gibi SSMS'in bu yeni versiyonu, güncellemeleri otomatik olarak yapabiliyor. Bunun yanında, aşağıdaki ekran görüntüsünde "Check for Updates…" menüsünü de görebilirsiniz. Eğer güncellemeleri kendiniz kontrol etmek isterseniz, bu yöntemi seçebilirsiniz.



SSMS'in özellikle Azure SQL Database ile birlikte gelecek olan yeni özellikleri destekleyebilmesi için ve bununla sınırlı kalmayarak SQL Server'ın kendi makinelerimizde kurulu olan versiyonlarındaki henüz desteklenmeyen bazı özelliklerin arayüz olarak desteklenmesi ve zaten var olan arayüzlerin iyileştirilmesi / geliştirilmesi için Microsoft'un bu hamlesi sevindirici. Böylece birçok iş için kullanıyor olduğumuz SSMS, genel SQL Server yüklemelerinden bağımsız bir hale geldi. Bakalım zaman, daha nelere gebe?

Ekrem Önsoy

10 Temmuz 2015 Cuma

Bir forum hikayesi: Shrink it and everything's gonna be fine...

Selam millet,

Dün (9 Temmuz 2015) birisi MSDN SQL Server forumlarında yaşadığı kapasite sorunuyla ilgili bir soru sordu, ibretlik olsun diye bunu bu yazımda irdelemek istiyorum.

Soru şöyle (Noktası virgülüne aynı):
"Hi all,
i've a server which is reside in remote area. my database store in drive E where disk capacity is 1000 GB and DB size reached 800GB , now disk free space showing 10 GB only . how to manage space.
couple of week back i've tried to shrink the database but it is not completed successfully and since the time db size drastically increase. now i'm sitting in corner. please help anyone to resolve this issues.
can we perform partial shrink only on MDF. so that we can manage the space (starting from 10 gb only)
if yes then please share the T-sql script."
Türkçesi:
"Herkese merhaba,

Uzaktaki bir sunucum var. Veritabanı E: diskinde ve kapasitesi 1TB ve veritabanının boyutu da 800GB'a ulaştı, şimdi diskteki boş alan sadece 10GB. Diskteki boşluk durumunu nasıl yönetebilirim?

Birkaç hafta önce veritabanını küçültmeye (Shrink) çalıştım, ama işlem başarıyla tamamlanmadı ve o zamandan beri veritabanının boyu ciddi şekilde arttı. Şimdi çaresiz kaldım, lütfen biri bu sorunu çözmem için yardımcı olsun.

Shrink işlemini sadece veri dosyaları (*.mdf) için yapabilir miyiz? Eğer öyleyse boş alan sorununun bu şekilde halledebiliriz.

Eğer böyle bi şey yapılabiliyorsa lütfen T-SQL Script'ini paylaşın."

Sorunun yorumu:
Şimdi bu sorudan hemen anlaşılıyor ki, bahsi geçen bu firmada bir SQL Server uzmanı yok. Muhtemelen her şeyle ilgilenmeye çalışan bir arkadaşa bu sorumluluk da verilmiş veya nispeten boyut olarak büyük sayabileceğimiz bu veritabanlarını yönetmek için bir Junior çalıştırıyorlar.

İlk gözlemler olarak şunları söyleyebilirim, bu arkadaş her şeyden önce kapasite planlaması yapmıyor. Veritabanlarının ortalama ne hızda büyüdüğünü bilmiyor. Shrink işleminin ne işe yaradığını ve sonuçlarını bilmiyor. Böyle bir durum ile önceden hiç karşılaşmamış.

Olabilir, profesyonel hayata dair sanırım hiçbir şeyi hiçbirimiz annemizin karnında öğrenmiyoruz. AMA! Sen gelmişssin uluslararası bir platformda bu sorununu paylaşmışsın. Sana defaatle "Güzel kardeşim, yapma, etme, Shrink senin sorununun çözümü değil" denmiş, ama belli ki bu konuda hiç tecrübesi olmayan biri "Shrink'e devam et sen kardeşim, iyidir" demiş ve sen çaresizce onu yapmaya devam etmişsin.

Sorunun ideal çözümü:
Dün ben ve başka arkadaşlar tekrar tekrar şunları önerdik:
- Mümkünse büyük ve gereksiz olan tablolardan temizlik yap,
- Eğer Transaction Log dosyanın boyutu çok büyükse, bunu en azından geçici bir süre için de olsa Shrink etmende sıkıntı yok (çünkü veri ve Transaction Log dosyaları aynı diskteydi),
- Yeni disk ekle! Çünkü Transaction Log dosyası veritabanının boyutuyla karşılaştırıldığında büyük değildi ve belli ki veritabanının büyümesi, tek seferlik bir işlemden kaynaklanan bir şişme durumu değildi.
- Eğer mümkünse, böyle bir durumda zaman kazanmak için Enterprise Edition kullanıyorsan (ve tabii CPU kaynakların da yeterliyse) Data Compression'ı düşünebilirsin.

Sonuç:
Şimdi bu sorunu yaşayan arkadaş dün heyecandan, çaresizlikten veya belki de yapabileceği hiçbir şey olmadığından veya saflğından diyeyim siz başka anlamlar yükleyin, bizim önerilerimiz yerine böyle bir sorun karşısında ısrarla Shrink'i öneren birisini dinledi. Böyle bir durumda Shrink'i önerebilecek biri, zaten hayatında 10GB'tan büyük veritabanı yönetmemiştir. Shrink'in tam olarak ne anlama geldiğini, ne zaman yapılabileceğini ve ne işe yaradığını da bilmiyordur. Fakat biz bunu, soru sorana anlatamadık. Sonra ne mi oldu? Devamı aşağıda.

Sorunu yaşayan arkadaş bu sabah (10 Temmuz 2015) şöyle iki cevap daha vermiş:

"big problem in front of me. disk space gradually decrease and application performance down,
now it is showing
Msg 904, Level 16, State 1, Line 1Database 11 cannot be autostarted during server shutdown or startup."

Türkçesi:
"Büyük bir sorunum var. Diskteki boş alan miktarı adım adım azaldı ve uygulama performansı da düştü. Şu anda şu hataları alıyorum:

Msg 904, Level 16, State 1, Line 1
Database 11 cannot be autostarted during server shutdown or startup.
"

Hemen akabindeki diğer mesajı:

"now while connecting to the database 
massage showing 'database vts not accessible'
help me to fix this issues"

Türkçesi:
"Şimdi, veritabanına bağlanmaya çalıştığımda 'Veritabanına erişilemiyor' hatası alıyorum.

Bu sorunları çözmem için yardımcı olun."

Bu saatten sonra yapabileceği tek şey artık çok daha zor koşullarda yeni bir disk eklemek, ardından ilgili dosya grupları için bu diske yeni dosyalar eklemek. Tabii ki veritabanına erişebilirse ve kesintinin yarattığı stres ile başa çıkabilirse.

İnsanlar bir gün elbette bu işin çocuk oyuncağı olmadığını anlayacak.

Ekrem Önsoy

8 Temmuz 2015 Çarşamba

SQL Server 2016: Live Query Statistics

Merhabalar,

SQL Server 2016 ile ilgili pek öne çıkmamış bir yenilikten bahsetmek istiyorum size, Live Query Statistics!

Live Query Statistics'i, sorgularınız ile ilgili performans sıkıntılarını çözmek için kullanabilirsiniz, zaten diğer zamanlarda kullanmayın, çünkü dokümantasyondaki uyarıya göre sorgunuzun performansını ciddi şekilde olumsuz olarak etkileyebilir. Kullanımı, aynen Include Actual Execution Plan'da olduğu gibi, yine hemen Include Actual Execution Plan simgesinin sağ tarafındaki Include Live Query Statistics simgesine tıklayarak gerçekleştirilmektedir. Aşağıda ekran görüntüsünü de bulabilirsiniz.

Live Query Statistics
Yukarıdaki ekran görüntüsünde de görebileceğiniz gibi önce Include Live Query Statistics simgesine tıklayıp etkinleştirin (Query Editor'de farenin sağ tuşuna tıklayarak veya Main Menu'deki Query alt menüsünden ulaşabilirsiniz bu özelliğe) ve sonra da sorgunuzu çalıştırın.

Eğer sorgunuz yeterince uzun sürüyorsa, karşınıza Live Query Statistics penceresi çıkacak ve burada ilgili operatörde ne kadar zaman geçirildiğini canlı olarak göreceksiniz. O anda hangi operatörde işlem yapılıyorsa ve işin yüzde kaçı tamamlandıysa, o anda o operatörün altında "… % done" yazıyor. Ayrıca sorgu çalışmaya başlar başlamaz da her operatörün altında aynı anda zaman işlemeye başlıyor ve hangi operatörde ne kadar zaman geçirildiyse o operatörün altına bu geçen zaman not ediliyor. Bunu daha iyi görebilmeniz için bir de aşağıdaki gibi sorgu çalışırken ekran görüntüsü aldım.

Live Query Statistics - While a query is being executed
Ayrıca en aşağıda artık sadece "Executing query…" yazmıyor, bunun hemen sağ tarafında da sorgunun toplamda yüzde kaçının tamamlandığı da yazıyor. Henüz çalışma sırası gelmeyen operatörlerin arasında ok değil, sola doğru hareket halinde (animasyonlu) noktalar var.

Dokümantasyonda da görebileceğiniz birkaç hatırlatmayı paylaşayım, Live Query Statistics Memory Optimized Table'larla, Natively Compiled Stored Procedure'larla ve Column Store Index'lerle kullanılamıyor. 

Live Query Statistics ile ilgili Books Online dokümantasyonuna buradan ulaşabilirsiniz.

Ekrem Önsoy

24 Haziran 2015 Çarşamba

Bir Tool daha... DBAToolkit

Selam!

Dosya arşivimde dolanırken buldum bu uygulamamı. Bu uygulamayı birkaç sene önce, çalıştığım bir şirkette eksikliğini gördüğüm bir uygulamada gördüğüm lüzum üzerine yazmaya başlamıştım. Sorunu maddelerle anlatayım:
- Yazılımcılara veya iş analistlerine, geliştirme, kalite kontrol ve üretim veritabanlarında kalıcı veya geçici yetkiler veriliyordu; fakat bu yetkilendirme işlemleri tamamen elle yapılıyor ve bu yetkilendirmelerin kayıtları bazı metin dosyalarında elle girilerek tutuluyordu. Verilen yetkilerin kayıtları metin dosyalarında tutulduğu için, verilen geçici yetkilerin geri alınmaları gerektiği zaman bu işlem atlanabiliyordu, tabii ki böyle bir işin takibi de çok zor oluyor.
- Yüzlerce veritabanı sunucusunun olduğu, işe giriş ve çıkış sirkülasyonunun da yoğun olduğu böyle bir ortamda tek tek SQL Server Instance'larına bağlanıp yetki vermek de çok zaman alıyordu.
- Hangi yetkinin kim tarafından, tam olarak ne zaman, kimin onayıyla, neye istinaden ve hangi açıklamayla verildiği bilinemiyordu.

Yukarıda sıraladığım temel sorunları çözmek için bir uygulama yazmaya karar verdim. Boş vakitlerimde uygulamayı adım adım geliştirdim. Uygulamayı kendim kullandığım için, işimi kolaylaştıracak özellikleri bulduğum boş bir vakitte hemen ekliyordum. Aynı şekilde bulduğum hataları da düzeltiyordum.

Zamanla uygulamayı tüm ekip arkadaşlarım da kullanmaya başladı. Tabii zamanla daha farklı ihtiyaçlarımız da oldukça, uygulamaya yeni bölümler ekleyerek bu ihtiyaçlarımızı da gidermeye başladık. Bu kadar konuşmanın ardından, en azından uygulamadan bir ekran görüntüsünü aşağıda paylaşmak istiyorum.

DBAToolkit
Bu gördüğünüz ekran, yetki verme işlemlerinin yapıldığı ekran. Uygulamanın bu hali, tamamen o şirkete özel halidir. Henüz paket programa çevirmedim, şimdilik öyle bir niyetim de yok. Bununla birlikte, biraz elden geçirmeyle yeni bir şirkete rahatlıkla uyarlanabilir ve hatta paket programa da çevrilebilir.

Yukarıdaki yetkilendirme ekranını aşağıda madde madde anlatayım. Şimdiden söyleyeyim vereceğim bilgiler özettir, uygulamanın daha birçok ayrıntısı bulunmaktadır.
- Yetkiler "Geçici" veya "Kalıcı" olarak verilir. Yetkinin alınacağı tarih "Alınma tarihi" alanında belirtilir.
- "Sunucu adı" listesinden sunucu seçildiğinde "Veritabanı adı" listesi otomatik olarak dolar, keza veritabanı seçildiğinde de "Roller" listesi seçili veritabanındaki Database Role'leriyle dolar. Bu işlem ve hedef sunucu ile ilgili yapılan tüm işlemler o anda uygulamayı kullanan kişinin Windows oturumu açtığı kullanıcı ile yapılır, bu nedenle yetkisiz bir kullanıcı bu uygulamayı zaten kullanamaz.
- "Açıklama" bölümüne, yetkinin kimin onayıyla verildiği bilgisi yazılabilir.
- "Çağrı numarası" alanına, yetkinin bir çağrı ile talep edildiği varsayılarak hangi çağrı kaydıyla talep edildiyse o çağrının numarası girilir. Böylelikle yetkilendirme işlemi, ilgili çağrı ile ilişkilendirilmiş olur ve örneğin teftiş yetkinin neye istinaden verildiğini sorduğunda kanıt hemen bulunabilir.
- Bazı senaryolarda, bazı sunuculara doğrudan uygulama ile erişemeyebilirsiniz ve yetkilendirmeyi o sunucuya RDP yapıp vermeniz veya başka bir şekilde vermeniz gerekebilir. Böyle durumlarda ise yetkilendirme işleminin yine de kayıt altına alınabilmesi için "Kayıt şekli" açılır kutusunda "Sadece kaydet" seçeneğini seçebilirsiniz. Eğer hem işlemi kaydetmek isterseniz hem de yetkiyi uygulamaya verdirtmek isterseniz o zaman "Kaydet ve yetkilendir" seçeneğini seçebilirsiniz.
- "Ara" düğmesini kullanarak önceden vermiş olduğunuz bir yetkiyi ID'sine, Çağrı numarasına, Kullanıcı adına göre veya iki tarih arasında arayabilirsiniz.
- "Yetkileri eşleştir" seçeneği ile, bir veritabanında (veya tüm veritabanlarında) DBAToolkit ile verilen yetkileri ve o veritabanlarında verilmiş yetkileri karşılaştırabilirsiniz. Böylece DBAToolkit ile verilmemiş, yani kayıt dışı yetkileri tespit edebilirsiniz.
- "Yetkilendirme listesi"ndeki kayıtların üstünde farenin sağ tuşuna tıklarsanız çeşitli seçenekler bulursunuz. Örneğin bazen kullanıcılar "işimi bitiremedim, yetki iznimin uzatılması gerekiyor" gibi taleplerle gelebiliyor, yöneticisi de onayladığında yetki alınma süresi gelmiş bir kaydın yetki alınma süresini 1-2 fare tıklamasıyla erteleyebilirsiniz.
- Aşağıdaki "İşlem tarihçesi" listesinde, yapılan işleme ait ayrıntılı bilgileri bulabilirsiniz. Örneğin yetki verilen kişinin önceden hedef SQL Server Instance'ında bir Login'i yoksa, bunun oluşturulduğu bilgisi, veritabanına önceden erişimi yoksa, veritabanı erişim yetkisinin verildiği, ilgili role üye yapılma onayı ve eğer işlem hata aldıysa alınan hata mesajı bu şekilde kaydedilir.
- "Listeleme kriterleri", "Yetkilendirme listesi"ndeki kayıtların ne şekilde listeleneceğini belirler. Örneğin sadece bu ayki kayıtlar veya son 100 kayıt gibi. Ayrıca sadece hata alan yetkilendirme işlemleri ve/veya geçici yetkilendirmelere ait işlemler de listelenebilir.

Yukarıdaki ekran görüntüsündeki her sekmeden ayrı ayrı bahsetmeyeceğim, ama bazılarından bahsedeyim,
- "Log Shipping" sekmesinde Log Shipping'lerinizin ne durumda olduğunu görebilirsiniz. Ne kadar geride kalmışlar, Restore'lar devam ediyor mu vs.
- "Disk talepleri" sekmesinde, SAN ekibinden yaptığınız disk taleplerini takip edebilirsiniz. Özellikle yoğun ortamlarda SAN ekiplerinden bol bol disk talepleri yaparız, yeni bir disk veya varolan diskin büyütülmesi gibi. Bu talepler için çağrılar açarız, fakat açtığımız çağrıların takibini yapmak, tabii ki kullandığımız Service Desk uygulamasına da bağlı olarak oldukça zor olabilir. Bu sekmeden yaptığımız talepleri takip etmemiz kolaylaşıyor.
- "Sunucu karşılaştır" sekmesini daha ziyade Side-by-side Upgrade işlemlerinde yeni kurduğumuz sunucu ile eski sunucunun Server Configuration ayarlarını karşılaştırmak için kullanıyordum. Örneğin X1 isimli sunucu varolan SQL Server 2008 sunucumuz, o anda adı X2 olan yeni donanımlı sunucumuz da SQL Server 2012 sunucumuz. X1 Instance'ındaki ayarlarımızı X2'ye aktarmak istediğimizde, bu sekme ile doğrudan iki Instance'ı karşılaştırabiliriz. Farklılıklar farklı renklerle işaretleniyor ve doğrudan ve tek tek X2 Instance'ına uygulanabiliyor.
- "Müşteriler" sekmesi, özellikle birden fazla müşteriniz olduğunda çok kullanışlı olabiliyor. Müşterilere ait sunucu ve kullanıcı isimleri, bunların hangi ortamlara (geliştirme, üretim vs) ait oldukları gibi bilgiler bu sekmeden yönetiliyor.

Bu yazıyı kısa kesmek için birçok şeyi sadece özet olarak paylaştım, her sekmenin veya özelliğin ekran görüntüsünü de paylaşamadım. Uygulama birçok açıdan daha da güzelleştirilebilir ve uygun bir ortam olduğunda bunu da yapacağım. Önceden belirttiğim gibi, uygulama bu haliyle ortam-spesifik olduğu için herhangi bir yerde paylaşamıyorum.

Nasıl? Bir DBA olarak bu uygulama hakkında ne düşünüyorsunuz? Kendi ortamlarınızda böyle bir uygulamaya ne kadar ihtiyacınız var?

Sevgiler,
Ekrem Önsoy


19 Haziran 2015 Cuma

The EXECUTE permission was denied on the object 'sp_sqlagent_update_agent_xps', database 'msdb', schema 'dbo'

HATA:
[298] SQLServer Error: 229, The EXECUTE permission was denied on the object 'sp_sqlagent_update_agent_xps', database 'msdb', schema 'dbo'. [SQLSTATE 42000] (DisableAgentXPs)

AÇIKLAMA:
SQL Server Agent servisini çalıştırmayı denediğinizde böyle bir hata ile karşılaşabilirsiniz. Sorun, SQL Server Agent servisini çalıştırması için kullandığınız Windows (Local veya Domain) hesabının ilgili SQL Server Instance'ında "sysadmin" Fixed Server Role üyesi olmadığından kaynaklanıyor.

ÇÖZÜM:
SQL Server Configuration Manager veya Services.msc'yi kullanarak SQL Server Agent servisi için hangi hesabın kullanıldığını bulabilirsiniz. Daha sonra bu hesap için, bu SQL Server Agent'ın bağlı bulunduğu SQL Server Instance'ınızda bir Login olduğuna ve bu Login'in de "sysadmin" Fixed Server Role'ünün üyesi olduğuna emin olun. Yetkiyi verdikten sonra SQL Server Agent servisini tekrar çalıştırmayı deneyebilirsiniz.


17 Haziran 2015 Çarşamba

SQL Server 2016'da bir başka tempdb değişikliği

Merhabalar,

Geçenlerde SQL Server 2016 ile birlikte, kurulum ekranından tempdb dosya sayısının arttırılabilir olduğundan bahsetmiştim.

Bildiğiniz gibi tempdb'de, özellikle yoğun ortamlarda yaşanan kronik SGAM (Shared Global Allocation Map) ve PFS (Page Free Space) çekişme sorunu vardır. Yeni bir nesne yaratıldığında ilk 8 sayfa için farklı Extent'ler kullanılıyor. Daha sonraki sayfalar için ise tek bir Extent kullanılıyor. SGAM sayfası da tüm bu Extent'leri takip etmek için kullanılıyor ve çok sık ve fazla yeni nesne oluşturulduğunda bu da sıkışıklığa neden oluyor. Bu sorunu TF 1118 kullanarak atlatıyoruz. Yine çok sık ve fazla nesnenin oluşturulduğu ortamlarda PFS sorunları yaşanıyor, bunu aşmak için de CPU sayımıza göre tempdb'ye yeni veri dosyaları ekliyoruz.

SQL Server 2016'da tempdb ile ilgili yapılan tek değişiklik yukarıda bahsettiğim kurulum ekranından tempdb için yeni veri dosyası eklemek değilmiş. SQL Server 2016'da tempdb'de yapılan tüm sayfa ayırma işlemleri aynı Extent'lerde gerçekleştirilecekmiş. Hal böyle olunca, SQL Server 2016'da artık TF 1118 kullanmamıza gerek kalmayacak. Gereği kadar veri dosyalarını da kurulumda eklersek, tempdb'de yaşanan kronik sorunların büyük bir kısmı işin en başında atlatılmış olacak.

Sevgiler,
Ekrem Önsoy

16 Haziran 2015 Salı

2 iş görüşme tecrübesi

Merhaba arkadaşlar,

Son 10 gündür iş görüşmeleri açısından biraz hareketli geçiyor, yabancı firmalarla yaptığım bu son 2 iş görüşme tecrübelemi sizlerle de paylaşmak istedim. Bugün, yarın sizin de böyle planlarınız olursa, az çok neyle karşılaşacağınız hakkında bir fikriniz veya tecrübenize tecrübe katar.

Öncelikle yaklaşık 10 gün önce Amsterdam'dan, Boeing'in iştiraki olan ve havacılık alanında yazılım üreten bir firma ile Skype üzerinden bir iş görüşmesi yaptık. Pozisyon, Senior SQL Server DBA pozisyonuydu. 160 kişilik bir şirket, 2 DBA'den biri olacakmışım. Standart, OLTP üretim veritabanı yöneticisinden beklenilenleri beklediklerini söylediler, kolayca bulunabileceği için madde madde yazmıyorum bunları.

Bunların karşılığında da bana, eşim ve benim için oturum ve çalışma iznini ayarlayacaklarını, benim için sağlık sigortası (150Eur) ödeyeceklerini (bunu bildiğim kadarıyla Hollanda'da insanlar genelde kendileri ödüyor), emeklilik fonuma para yatıracaklarını (bu da orada senelerce yaşamış olan teyzemin dediğine göre genelde yabancılara yapılmıyormuş), toplu taşıma masraflarımı ödeyeceklerini, senelik bir maaş kadar tatil parası vereceklerini, biraz da ikramiye vereceklerini söylediler. Her fırsatta Hollanda'ya gittiğim için oradaki masrafları biliyorum, net ücret teklifleri maalesef ihtiyaçların çok gerisinde kaldığı için o teklifi kabul edemedim. Hollanda'ya iş için göçecek arkadaşlarıma tavsiyem, özellikle eşinizle gidecekseniz küçük de olsa mobilyalı bir ev tutmanız gerekecek. Bunun için de (tabii ki yerine göre değişir) ortalama 1250-1700 Euro gibi bir ev kirası ödeyeceğinizi unutmayın. Eğer tek gidecekseniz oda da kiralayabilirsiniz, Hollanda'da bu çok yaygındır ve bunun için de 300-500 Eur arasına anlaşabilirsiniz. Yani tabiri caizse "aa ne güzel maaş xxx Eur'muş lan" deyip balıklama atlamayın, hesabınızı kitabınızı iyi yapın.

Bugün de Hindistan menşeli bir firma ile Senior SQL Server Escalation Engineer pozisyonu için telefonda teknik mülakat yaptık. Hemen söyleyeyim, bu pozisyon için Hindistan'a taşınmam beklenmiyor. Microsoft CSS (Customer Service & Support)'u biliyorsanız, onun gibi. Sene 2010 idi sanırım, Microsoft CSS için de iş görüşmesi yapmıştık, fakat o zaman da çalıştığım kurum tabiri caizse "taş koyduğu" için olmamıştı o iş. Açıkçası Hollanda ile yaptığım iş görüşmesinden önce de Skype üstünden yurtdışındaki bazı firmalarla iş görüşmeleri yapmıştım; ama ilk defa telefonla bir teknik mülakat yaptım. İlginç bir tecrübe oldu. Skype ile iş görüşmesi yaptığınızda yine birisinin yüzünü, gözünü görüyorsunuz; fakat telefonda sadece ses var. Hintlilerin şivesini bilen bilir, neyse ki yıllardır Hintlilerin verdiği seminer ve konferanslardan kulağımız aşina, yoksa ilk duyan birisi için gerçekten zorlayıcı olabilir; hele ki bir de telefondan sesin boğuk geldiğini düşünürseniz, gerisini siz hesap edin…

Neyse, bu mülakatta bana sorulan soruların başlıklarının aklımda kalan kadarını sizlerle paylaşayım.
- Bir DBA olarak günlük yaşadığın sorunlar nelerdir?
- Log Shipping, Database Mirroring, Replication gibi teknolojileri kullandın mı?
- Replication'ın hangi modellerini kullandın?
- Replication'da karşılaştığın bazı sorunlardan bahseder misin?
- Failover Clustered Instance'larla çalıştın mı?
- Bir Cluster'daki Node'larda güncelleme yapacağın zaman, kesinti süresini en aza indirmek için neler yaparsın?
- Bir SQL Server Instance'ını Komut İstemcisi'nden nasıl çalıştırırsın?
- Bir SQL Server Instance'ını kullanıcı veritabanlarını açmadan nasıl çalıştırırsın?
- Policy Based Management'tan günlük işlerinde faydalanıyor musun?
- İstatistikler ne işe yarar?
- Index bakımını ne sıklıkta yapıyorsun ve bu işlemi neden yapman gerekiyor?
- Bir TempDB'yi nasıl yapılandırırsın?
- Örneğin bir yazılımcı veya kullanıcı seni aradı, şu şu SP geçen hafta iyi çalışıyordu, ama bu hafta rezalet dedi, ne yaparsın? Sorunlu SP'yi nasıl bulursun? Bu SP'ye nasıl müdahale edersin?
- Bana RAID'lerden bahseder misin? Örneğin Transaction Log'unu nasıl bir RAID yapılandırmasında barındırmak isterdin? Neden?
- Bir sunucuya tam erişimin var ve sana bu sunucunun CPU, RAM ve IO kaynaklarında sıkıntı olduğu söylendi, bunları kontrol etmen gerekiyor, ne yaparsın? Hangi uygulamayı kullanırsın?
- Kullandığın 3. parti uygulamalar var mı? Örneğin yedekleme veya sistem izleme için? Varsa bunlardan bahseder misin?
- Sistem izleme konusunda neler yapıyorsun, hangi Tool'lardan faydalanıyorsun, nasıl tedbirler alıyorsun?
- SQL Server Instance düzeyinde CPU ve RAM ile yapılabilecek yapılandırma ayarlarından bahsedebilir misin?
- Ne zamandan beri sorgu iyileştirme çalışmaları yapıyorsun? Bir sorguyu iyileştirmek için neler yaparsın?
- Deadlock'ları nasıl tespit edersin?

Not: Mülakat 40dk sürdü. Soruları, bana sorulan sıraya göre değil, şimdi aklıma geldiği sırada yazdım.

Açıkçası ben şu konu başlıklarından da soru gelmesini beklerdim, ama bu sefer gelmedi:
- Index yapıları ve çeşitleri
- AlwaysOn Availability Groups
- Table Partitioning
- Service Broker
- Dynamic Management View/Function'lar
- SQL Server'da Güvenlik
- Yedekleme stratejileri
- High Availability ve Disaster Recovery senaryoları
gibi...

Aklımda bunlar kalmış, sıcağı sıcağına yazayım en azından meraklılar için bir fikir verir dedim.

Bu arada, aklıma geldi de yazmadan edemedim. Sene 2011 idi sanırım, o zaman bizim bölüm müdürü olan arkadaş bir aday ile iş görüşmesine girmişti. Görüşmede bizim müdür, adaya "Cluster'lar hakkında ne düşünüyorsun?" diye sormuş ve aday da "Bence gereksizler" demiş. Bizim müdür bana şöyle demişti "Benim için iş görüşmesi o anda bitmişti". Haha ne gülmüştüm. Lütfen böyle durumlara düşmemek için dersinizi iyi çalışın. Hepinize mutlu kariyerler, mutlu ve huzurlu hayatlar dilerim!

Sevgiler,
Ekrem Önsoy