Arşiv

Etiketlenen yazılar SQL

Bu kodda ne yanlış var? – 6

Bir kitabevi için web uygulaması geliştiriyorsunuz. Yaptığınız analize dayanarak, uygulamanın veritabanını aşağıdaki gibi tasarladınız;

Bu kodda ne yanlış var? - 6 / Veritabanı Modeli

Veritabanı modelinize göre, her kitabın sıfır veya daha fazla yazarı olabilir, her yazarın sıfır veya daha fazla kitabı olabilir.

Toplam Kitap Adedi ve Toplam Yazar Adedi sorularına cevap verebilmek için, aşağıdaki sorguyu yazdınız;

SELECT DISTINCT
	COUNT(Yazarlar.YazarID) AS ToplamYazarAdedi,
	COUNT(Kitaplar.KitapID) AS ToplamKitapAdedi
FROM
	Yazarlar
	FULL JOIN YazarKitaplari YK ON Yazarlar.YazarID = YK.YazarID
	FULL JOIN Kitaplar ON YK.KitapID = Kitaplar.KitapID

Problem, rakamların beklediğinizden yüksek çıkması.

Sizce problem nedir ve nasıl düzeltebiliriz?

Sql Server veritabanında en büyük 10 tablo

Sql Server‘da belli bir veritabanında en büyük tabloları bulmak için aşağıdaki sorguyu çalıştırabiliriz;

DECLARE @TabloBoyutlari TABLE (TabloAdi VARCHAR(50), SatirSayisi INT, AyrilmisAlan VARCHAR(50), KullanilanAlan VARCHAR(50), IndexBoyu VARCHAR(50), KullanilmayanAlan VARCHAR(50))

INSERT INTO @TabloBoyutlari
EXECUTE sp_MSforeachtable 'sp_spaceused [?]'

SELECT TOP 10 * FROM @TabloBoyutlari ORDER BY CONVERT(INT, REPLACE(AyrilmisAlan, ' KB', '')) DESC

Bu sorgu sayesinde ilgili veritabanındaki tabloların,

  • Tablo Adı
  • Satır Sayısı
  • MDF dosyasında ilgili tablo için ayrılmış alanın boyutu
  • MDF dosyasında ilgili tablo için ayrılmış alanın kullanılan boyutu
  • MDF dosyasında ilgili tablonun indexleri için ayrılmış alan
  • MDF dosyasında ilgili tablo için kullanılmayan alan

bilgilerine ulaşabiliriz.

İlgili tablo için aşağıdaki eşitlik her zaman doğrudur;

Kullanılan Alanı + Index Alanı + Kullanılmayan Alanı = Ayrılmış Alan

Benim bilgisayarımdaki AdventureWorks2008R2 örnek veritabanında yukarıdaki sorguyu çalıştırdığımda, şöyle bir sonuç alıyorum;

Sql Server - Veritabanında en büyük 10 tablo

Uzman TV Röportajlarım – 1 (Sql Server)

Uzman TV ile yaptığımız Sql röportajlarında bana sordukları sorular ve cevaplarım;

SQL nasıl bir veritabanı dilidir? (SQL nasıl ortaya çıktı? Kim tarafında bulundu? Veritabanı nedir?)

Önce veritabanı ne demektir, ondan bahsetmek lazım. Veritabanı, bilgisayar ortamında bir düzen ile saklanan, programatik erişim imkanı bulunan, yönetilebilir, güncellenebilir, birbirleri arasında ilişkiler tanımlanabilir, bilgiler kümesidir.

SQL, ilk olarak IBM Research Center tarafından DB2 veritabanı ailesi için geliştirilmiştir. Daha sonra SQL dili, ANSI tarafından standartlaştırılmıştır.

Türkçe açılımı Yapılandırılmış Sorgu Dili anlamına gelmektedir. Verileri ve veri kümelerini modellemek ve yönetmek için kullanılır.

SQL, tanımlı anahtar kelimelerden oluşturulan sql cümleleri ile, veritabanına kayıt ekleyebilir, güncelleyebilir, silebilir veya varolan kayıtları listeleyebilir.

Microsoft Sql Server, Oracle ve hatta Access kendi SQL cümle yapısına yani diyalektiğine sahiptir.

Hangi tür şirketler SQL’den yararlanabilir? (Veritabanı uygulamalarını tercih eden firmalar nelerdir? SQL kullanması gereken uygulamalar hangileri?)

Günümüzde bilgisayar ve dolayısıyla yazılım kullanmayan, bunlara ihtiyaç olmayan iş kolu kalmadı. Ne kadar küçükte olsa, ne kadar büyükte olsa, her alandaki her firmanın mutlaka bilgisayar ve yazılım kullan birimleri vardır.

Genelde firmalar, kullandıkları bilgisayar programlarının verileri güvenli bir ortamda kaydetmesini, daha sonra aradığında bulabilmesini, gerekirse analiz edebilmesini, yaptığı analize ilişkin raporlar üretebilmesini beklemektedir.

Veritabanı uygulamaları kullanmadan böyle bir işlevselliği sağlayabilmek olanaksız olmasa da çok zor olacağından, hemen hemen tüm firmaların bir veritabanı yönetim sistemine ihtiyacı vardır diyebiliriz.

Bu açıdan bakacak olursak, ticari değer taşıyan hemen hemen tüm uygulamaların ve web sitelerinin veritabanına ihtiyacı vardır.

Şirketler kendilerine uygun veritabanı uygulamasını nasıl seçmeli? (Küçük ve orta ölçekli şirketler açık yazılımlar mı tercih etmeli? Veritabanı desteği veren firmalar var mı?)

Küçük ve orta şirketli firmalar genel de ücretsiz olan açık kaynak kodlu veritabanı yönetim sistemlerini tercih etmektedirler.

Daha büyük ölçekli firmalar ise, hem donanım, hem işletme, hem de personel maliyetlerini göze alabilerek, ücretli veritabanı yönetim sistemlerini tercih edebilirler.

Açık kaynak kodlu veritabanı yönetim sistemlerinin, genelde desteğini veren firma bulmak zordur. Örneğin, bugün piyasada MySql desteği veren firma bulmak hakikatten zordur.

Microsoft Sql Server, Oracle, IBM DB2 gibi veritabanı yönetim sistemlerinin ise, desteği üretici firmaların Türkiye acentelerinden edinilebilir.

Firmalar, Microsoft Sql Server’ın desteğini, Microsoft Türkiye’den, Oracle’ın desteğini Oracle Türkiye’den, IBM DB2’nun desteğini IBM Türkiye’den alabilirler.

Veritabanı uygulamaları arasında ne tür farklar var? (MySQL, Windows SQL gibi programlar nasıl karşılaştırılmalı? Eksik ve fazlaları nasıl değerlendirilmeli?)

Microsoft’un Microsoft Sql Server ve Sql Express uygulamaları, Oracle’ın Oracle uygulaması, IBM’in DB2 uygulaması, gene Microsoft’un Access uygulaması ve açık kod olan MySQL uygulaması veritabanı yönetim sistemlerine örnektir.

Bu veritabanı yönetim sistemleri içinde ücretsiz olanlar vardır; Microsoft’un Sql Express versiyonu gibi. Bu ücretsiz veritabanı yönetim sistemleri genelde bazı kısıtlara sahiptirler. Örneğin, sunucunun hafızasının ve işlemcisinin sadece belli bir miktarını kullanabilirler, belli boyuta kadar veri saklayabilirler, gibi.

Ölçeklendirecek olursak, “büyük” ölçekli diyebileceğimiz Microsoft Sql Server, Oracle, IBM DB2 gibi veritabanı yönetim sistemleri, hem satın alma anlamında, hem de çalışmak için ihtiyaç duyduğu donanım ve yönetim için için gerekli personel maliyeti anlamında pahalıdır.

Bunların yanında MySql gibi, açık kaynaklı yazılımlar sayesinde, düşük maliyetli veritabanı yönetim sistemi sahibi olunabilir.

Sql Server’da Random Sayı Üretmek

C# tarafında rastgele sayıya ihtiyacımız olduğunda Random class’ından yeni bir nesne üretip kullanabiliyoruz. Eğer rastgele sayıya Sql tarafında ihtiyacımız olursa yapmamız gereken, RAND() fonksiyonunu kullanmaktır.

RAND() fonksiyonu ile ilgili detaylı bilgiye MSDN‘de yeralan şu makaleden ulaşabilirsiniz.

RAND([seed]) fonksiyonu parametre olarak seed değeri alabilir ve geriye float tipinde sonuç döner.

seed parametresi int, smallint veya tinyint tipinde olabilir.

RAND() fonksiyonu aynı seed değeri ile her çalıştırıldığında aynı “rastgele” sayıyı döndürür. Eğer seed verilmezse, Sql Server rastgele bir seed değeri atayarak, “rastgele” sayı oluşturur.

Eğer RAND() fonksiyonundan float tipinde noktalı sayı değil, int tipinde tamsayı dönmesini istiyorsak, basit bir convert işlemine tabi tutabiliriz;

SELECT CONVERT(INT, RAND() * 100)

Sql Server İstatistiklerin Son Güncellenme Zamanını Bulma

İstatistikler, verinin veritabanı nesnelerinde (tablo, index, vs) nasıl dağıldığı bilgisini içerdiği için, veritabanında en önemli nesnelerden biridir.

Veritabanı Yöneticilerinin (Database Administrators) eskimiş istatistiklerden şikayetlerini çok duydum. Yapılması gereken istatistikleri güncellemektir.

Eğer bir tablodaki indexlere ait istatistiklerin son güncelleme zamanını öğrenmek istiyorsanız, aşağıdaki sql sorgusunu çalıştırabilirsiniz;

SELECT
	NAME AS INDEX_ADI,
	STATS_DATE(OBJECT_ID, INDEX_ID) AS SON_GUNCELLEME
FROM
	SYS.INDEXES
WHERE
	OBJECT_ID = OBJECT_ID('HumanResources.Department')

Eğer tüm indexler için aynı bilgiyi almak istiyorsanız, WHERE filtresini kaldırmanız yeterli.

Benim test bilgisayarımda aldığım sonuç;

PK_Department_DepartmenID 2010-01-20 15:30:17:200
AK_Department_Name 2010-01-20 15:30:26:053

Eğer istatistiklerinizin zamanı geçmiş olduğunu düşünüyorsanız ve güncellemek istiyorsanız, aşağıdaki sql komutunu çalıştırabilirsiniz;

UPDATE STATISTICS HumanResources.Department

Bu komutu çalıştırdığınızda ilgili tablonun istatistik verilerinin güncellendiğini göreceksiniz. Eğer komutu WITH FULLSCAN komutu ile birlikte çalıştırırsanız, tablodaki tüm kayıtlar baştan taranacak ve istatistik baştan oluşturulacaktır.

UPDATE STATISTICS HumanResources.Department
WITH FULLSCAN

Dikkat : İstatistikleri güncellemek için yukarıdaki komutları, sadece istatistiklerinizin gerçekten eskimiş olduğuna inandığınızda, sorgularınız için oluşturulan query plan’ların hatalı olduğunu gördüğünüzde ve sql server’ın yoğun olmadığı zamanlarda çalıştırmanızı tavsiye ederim.

Kendi test bilgisayarımda, istatistik güncelleme komutunu çalıştırdıktan sonra, aşağıdaki sonuçları elde ettim;

PK_Department_DepartmenID 2010-01-30 21:10:06:560
AK_Department_Name 2010-01-30 21:10:06:594

Gördüğünüz gibi, ilgili tablodaki indexlerin istatistikleri güncellendi.

Sql Server SET NOCOUNT komutu

Sql Server‘da her sorgu çalıştırdığımızda, sorgu sonucu, etkilenen satır sayısı ile birlikte, sorguyu çalıştıran uygulamaya geri gönderilir.

Bazı durumlarda bu bilgi işimize yarasa bile, genellikle kullanmayız.

Sql Server‘ın bu bilgiyi hesaplamasını ve uygulamaya geri göndermesini engelleyerek, çok ufakta olsa kazanç sağlayabiliriz.

Yapmamız gereken, sorgudan önce aşağıdaki komutu çalıştırmak olacaktır;

SET NOCOUNT ON

Sql Server sadece ilgili sorgu için, etkilenen satır sayısını hesaplama işlemini yapmayacaktır.

Sql Server Query Plan Cache

Sql Server‘da çalıştırılan her sorgu, aslında çalıştırılmadan önce derleme (compile) işlemine tabi tutulur. Bu derleme işlemi sonucunda Sql Server query plan denilen çıktıyı üretir.

Query Plan, query processor‘e (sorguyu işleyen birim), sorgunun ihtiyaç duyduğu veriler için veritabanında bulunan tablo ve index‘lere fiziksel olarak nasıl erişebileceğini söyler.

Fakat, query plan elde etmek için yapılan bu derleme işlemi, bazı sorgular için çok pahalı olabilir.

Sql Server, aynı sql sorgusunun defalarca çalıştırıldığı durumlarda, derleme işleminin yükünü azaltmak için, query plan cache denilen hafıza bölgesinde query plan‘ları önbellekler.

Query plan cache, önbellekleyeceği sorguları basit bir hash tablo‘da saklar. Hash tablo’nun iki alanı vardır, birinde sql sorgusunun kendisini, diğerinde derleme sonucu ortaya çıkan query plan‘ı saklar.

Sql Server, yeni bir sorgu çalıştıracağı zaman, ilk önce query plan cache‘te sorgunun query plan‘ı var mı diye bakar. Eğer bulursa, daha önce önbelleklenmiş bu query plan‘ı kullanır. Bulamazsa, ilk önce sorguyu yazım denetimine tabi tutar, sonra sorguyu derler ve oluşan query plan‘ı bu listeye ekler.

Query plan cache‘in getirdiği performans artışını ölçmek için, öncelikle Sql Server’daki query plan cache’i boşaltacağız;

DBCC FREEPROCCACHE

Dikkat : Bu komutu kullandığınızda, Sql Server üzerinde bulunan tüm query plan cache silinir. Veritabanı veya belli bir sorgu için temizleme mümkün değildir. Bu komutun Canlı Veritabanında (Production Database) kullanılmaması önerilir.

Şimdi Sql Server’ın sorguyu inceleme ve derleme işlemi için ne kadar vakit harcadığını bulmamız lazım. Yapmamız gereken, sorguyu çalıştırmadan önce aşağıdaki komutu çalıştırmak;

SET STATISTICS TIME ON

Şimdi sorgumuzu çalıştırabiliriz. Ben Sql Server 2008 için hazırlanmış örnek veritabanında (AdventureWorks 2008R2) aşağıdaki sorguyu çalıştırıyorum;

SELECT * FROM HumanResources.Employee WHERE BusinessEntityId IN (1, 2);

Sorgu sonucu;

SQL Server parse and compile time:
	CPU time = 0 ms, elapsed time = 12 ms.

(2 row(s) affected)

SQL Server Execution Times:
	CPU time = 0 ms,  elapsed time = 1 ms.

Gördüğünüz gibi, sorgunun parse ve compile işlemine tabi tutulması 12 ms. sürdü. Sorgunun çalıştırılması ise 1 ms. sürdü.

Aynı sorguyu tekrar çalıştırırsak, elde edeceğimiz sonuç;

SQL Server parse and compile time:
	CPU time = 0 ms, elapsed time = 1 ms.

(2 row(s) affected)

SQL Server Execution Times:
	CPU time = 0 ms,  elapsed time = 1 ms.

Query plan cache sayesinde, parse ve compile işlemi 12 ms. yerine 1 ms. sürdü.

Not : Sql Server’ın istatistik toplarken ulaşabileceği en düşük kesinlik süresi 1 ms.’dir. 1 ms.’den kısa süren işler için bile Sql Server 1 ms. raporlar.

Sql Server 2008 MERGE Operatörü

19 Ocak 2010 1 yorum

Sql Server 2008 ile hayatımıza yeni bir operatör geldi : MERGE.

MERGE Operatörü koşullu olarak INSERT ve UPDATE yerine geçen bir operatördür.

İşlem yapmak istediğiniz kaydın varlığına bağlı olarak INSERT veya UPDATE işlemlerinden birisini gerçekleştirir.

Eskiden bu işi gerçekleştirmek için, her satır için çalışan bir döngü içerisinde satırın varlığını kontrol ettirdiğimiz IF kontrolü olurdu, ya INSERT cümlesini ya da UPDATE cümlesini çalıştırırdık.

MERGE operatörünün ana kullanım alanı DataWarehouse‘lar olacaktır.

OLTP mimarisinde veritabanınız içinde bulunan verilerinizin, OLAP mimarisinde veritabanınıza işlemek istediğinizde, varolan satırları UPDATE etmek, varolmayan satırları INSERT etmek istersiniz.

MERGE operatörü, bu karmaşık yapının oldukça basitleşmesini sağlıyor.

Kullanım şablonu;

MERGE INTO Tablo
USING (SELECT Cümlesi)
	WHEN MATCHED THEN
		UPDATE Cümlesi
	WHEN NOT MATCHED THEN
		INSERT Cümlesi

AdventureWorks 2008 veritabanında bulunan Production.UnitMeasure tablosunda bu özelliği nasıl kullanabileceğimizi bir örnek ile inceleyelim;

MERGE Production.UnitMeasure AS T
USING (SELECT 'KG', 'Kilogram') AS S (UnitMeasureCode, Name) ON (T.UnitMeasureCode = S.UnitMeasureCode)
	WHEN MATCHED THEN
		UPDATE SET Name = S.Name
	WHEN NOT MATCHED THEN
		INSERT (UnitMeasureCode, Name) VALUES (S.UnitMeasureCode, S.Name)

Sql Server COUNT ve COUNT_BIG Fonksiyonları

COUNT() sistem fonksiyonu, parametre olarak aldığı alandaki satır sayısını INT tipinde geri döndürür.

COUNT_BIG() sistem fonksiyonunun COUNT() fonksiyonundan farkı, elde ettiği sonucu BIGINT tipinde geri döndürmesidir.

INT veritipinin sınırları : -2^31 (-2,147,483,648) – 2^31-1 (2,147,483,647)

BIGINT veritipinin sınırları : -2^63 (-9,223,372,036,854,775,808) – 2^63-1 (9,223,372,036,854,775,807)

Eğer elde edeceğiniz sonucun INT veritipinin sınırlarına sığmayacağını düşünüyorsanız, yapmanız gereken COUNT_BIG() fonksiyonunu kullanmaktır.

Sql Server 2008′de Çoklu Insert İşlemi

19 Ocak 2010 1 yorum

Sql Server 2008 ile birlikte Çoklu Insert (Multiple Insert) özelliği de hayatımıza giriyor.

Microsoft bu özelliğin altında yatan tekniğe, “Table Value Costructor” adını vermiş.

Çoklu Insert (Multiple Insert) özelliği sayesinde Insert yapan DML cümlelerinde, birden fazla satırı işleme tabi tutabiliyoruz.

AdventureWorks 2008 veritabanında bulunan HumanResources.Department tablosunda bu özelliği nasıl kullanabileceğimizi bir örnek ile inceleyelim;

INSERT INTO
	HumanResources.Department
VALUES
	('İnsan Kaynakları', 'IK', GETDATE()),
	('Bilgi İşlem', 'IT', GETDATE()),
	('Muhasebe', 'MUH', GETDATE()),
	('Finans', 'FIN', GETDATE()),
	('Lojistik', 'LOJ', GETDATE()),
	('Kalite ve Eğitim', 'KVE', GETDATE())

Sql Server’da En Meşgul Veritabanını Bulmak

Geçenlerde bir öğrencimin sorusu üzerine Sql Server’da en meşgul veritabanını nasıl bulabiliriz, sorusuna cevap arayacağız.

En meşgul veritabanı, muhtemelen en çok disk operasyonu yapan veritabanıdır diye düşünerek, en çok disk aktivitesinde bulunan veritabanını yakalamaya çalışmalıyız.

Sql Server ile ilgili aradığımız birçok sorunun cevabını DMV‘lerde olduğu için, öncelikle logical_read ve logical_write miktarlarını veren DMV bulmalıyız.

MSDN’de şu sayfadan detaylı bilgiye ulaşabileceğiniz SYS.DM_EXEC_QUERY_STATS, ihtiyacımız olan TOTAL_LOGICAL_READS, TOTAL_LOGICAL_WRITES, SQL_HANDLE isminde üç kolona sahip.

SQL_HANDLE kolonunda yer alan veriyi, veritabanını bulmak için kullanabiliriz. Yapmamız gereken SYS.DM_EXEC_SQL_TEXT DMF‘i ile CROSS JOIN işlemine tabi tutarak, DBID kolonuna erişmek. Böylece DB_NAME sistem fonksiyonu sayesinde veritabanının ismine ulaşabiliriz.

SELECT
	SUM(EQS.TOTAL_LOGICAL_READS) AS TOPLAM_OKUMA,
	SUM(EQS.TOTAL_LOGICAL_WRITES) AS TOPLAM_YAZMA,
	ISNULL(DB_NAME(EST.DBID), 'AdhocSQL') AS VERITABANI
FROM
	SYS.DM_EXEC_QUERY_STATS AS EQS
	CROSS APPLY SYS.DM_EXEC_SQL_TEXT(EQS.SQL_HANDLE) AS EST
GROUP BY
	DB_NAME(EST.DBID)

Sql Server’da Hash işlemi

Uygulamalarımızda verileri hash‘lemeye her zaman ihtiyaç duyarız. Verileri hash’lemek için kullanabileceğimiz birçok araç vardır.

Eğer veriyi veritabanı katmanında (Sql Server) hash’lemek istiyorsak, MSDN‘de şu sayfada bulunan makalede okuyabileceğiniz gibi HASHBYTES fonksiyonu ile  yapabiliriz.

HASHBYTES fonksiyonu iki parametre alır;

Algoritma: Hash’leme algoritması. Alabileceği değerler; MD2, MD4, MD5, SHA, SHA1

Veri: Hash işlemine tabi tutulacak veri

HASHBYTES fonksiyonu geriye VarBinary(8000) tipinde değer döndürür.

MD5 algoritması ile hash işlemi yapan örnek kod;

SELECT
	KULLANICI_KODU,
	KULLANICI_ADI,
	HASHBYTES('MD5', KULLANICI_SIFRE) AS KULLANICI_SIFRE
FROM
	T_KULLANICI WITH (NOLOCK)
CREATE PROCEDURE PR_KULLANICI_EKLE
(
	@KULLANICI_KODU VARCHAR(5),
	@KULLANICI_ADI VARCHAR(50),
	@KULLANICI_SIFRE VARCHAR(15)
)
AS
INSERT INTO T_KULLANICI
	(KULLANICI_KODU, KULLANICI_ADI, KULLANICI_SIFRE, KAYIT_TARIHI)
VALUES
	(@KULLANICI_KODU, @KULLANICI_ADI, HASHBYTES('MD5', @KULLANICI_SIFRE), GETDATE())

SELECT SCOPE_IDENTITY()
CREATE PROCEDURE PR_KULLANICI_LOGIN
(
	@KULLANICI_ADI VARCHAR(50),
	@KULLANICI_SIFRE VARCHAR(15)
)
AS
SELECT
	KULLANICI_KODU,
	KULLANICI_ADI,
	HASHBYTES('MD5', KULLANICI_SIFRE) AS KULLANICI_SIFRE
FROM
	T_KULLANICI WITH (NOLOCK)
WHERE
	KULLANICI_ADI = @KULLANICI_ADI AND
	KULLANICI_SIFRE = HASHBYTES('MD5', @KULLANICI_SIFRE)

Güvenlik ihtiyaçlarından ötürü kıymetli bilgilerin network’ten ulaşılmasını önlemek için, veriyi taşımadan önce hash‘lemek isteyebilirsiniz. HASHBYTES fonksiyonu bu işin son derece kullanışlı gözüküyor.

Not : Yazıyı yazdıktan sonra gördüm ki, Emre Ayrılmaz şuradaki makalesinde aynı konuyu işlemiş, okunmasında fayda var.

Bu kodda ne yanlış var? – 1

04 Ocak 2010 7 yorum

Database’de şu scripti çalıştıralım;

CREATE TABLE T_PERSONEL
(
  ADSOYAD VARCHAR(50),
  DOGUM_TARIHI SMALLDATETIME
)

INSERT INTO T_PERSONEL VALUES ('Engin POLAT',  '1981-01-12')
INSERT INTO T_PERSONEL VALUES ('Emre ERKAN', '1979-03-14')
INSERT INTO T_PERSONEL VALUES ('Ozan ÇAĞLARGİL',  '1982-09-27')
INSERT INTO T_PERSONEL VALUES ('Fatih DURGUT',  '1978-06-23')
INSERT INTO T_PERSONEL VALUES ('Burhan İNEGÖL',  '1980-11-08')

Aşağıdaki stored procedure’i yazalım.

CREATE PROCEDURE PR_PERSONEL_LISTE
(
  @SIRALAMA INT
)
AS
BEGIN
  SELECT ADSOYAD, DOGUM_TARIHI FROM T_PERSONEL
  ORDER BY
    CASE @SIRALAMA
      WHEN 1 THEN DOGUM_TARIHI
      WHEN 2 THEN ADSOYAD
    END
END

Bu procedure’ü 1 parametresi vererek çalıştırıyoruz, ve beklediğimiz sonucu alamıyoruz.

Nerede hata yaptık? (İpucu; parametre olarak 2 vermeyi deneyin)

Yorumlarınızı bekliyorum…

Kısa Sınav – 9

Sql Server’da veritabanında zaten varolan bir tabloya yeni bir alan eklemek istiyorsunuz. Yeni ekleyeceğiniz alanda, PersonelNo bilgisini saklayacaksınız.

PersonelNo bilgisi herzaman 5 karakterden oluşuyor. Dünya üzerinde çeşitli ülkelerde çalışan yüzlerce çalışanınız olduğu için, PersonelNo alanında saklayacağınız bilgiler genelde Unicode karakterlerden oluşuyor.

PersonelNo alanı için en uygun veritipi ne olmalı?

  • nvarchar(5)
  • varchar(50)
  • nchar(5)
  • char(5)

Sorunun doğru cevabı için; Devamını oku…

@@IDENTITY, SCOPE_IDENTITY() ve IDENT_CURRENT() arasındaki farklar

Sql Server’da Identity kolon içeren tablolar ile çalışırken, yeni üretilen identity değerine ihtiyacımız olur.

@@IDENTITY, SCOPE_IDENTITY() ve IDENT_CURRENT() aynı işi farklı yöntemlerle yapar; son üretilen identity değerini döndürmek.

SELECT @@IDENTITY
Açılmış olan bağlantıda son üretilen identity değerini döndürür. @@IDENTITY tablo ve scope bakmaksızın, connection’da üretilen son identity’yi verir. Dikkat : Eğer Insert yaptığınız tablo’da Trigger varsa, yanlış identity alabilirsiniz.

SELECT SCOPE_IDENTITY()
Açılmış olan bağlantıda ve sorgunun çalıştığı scope’ta son üretilen identity’yi döndürür. Trigger kullanılan tablolarda @@IDENTITY yerine SCOPE_IDENTITY() kullanılması tavsiye edilir.

SELECT IDENT_CURRENT(tablename)
Bağlantı ve scope bakmaksızın, parametre olarak verilen tabloda üretilen son identity değerini döndürür.

Örnek;

CREATE TABLE TEST_TABLO_1
(
	ID INT NOT NULL IDENTITY (1, 1),
	ACIKLAMA VARCHAR(500) NULL,
	BILGI VARCHAR(1000) NULL
)

CREATE TABLE TEST_TABLO_2
(
	ID INT NOT NULL IDENTITY (1, 1),
	ACIKLAMA VARCHAR(500) NULL,
	EKSTRA_BILGI VARCHAR(1000) NULL
)

GO

CREATE TRIGGER TRG_TEST ON TEST_TABLO_1
FOR INSERT
AS
INSERT INTO TEST_TABLO_2
	(ACIKLAMA, EKSTRA_BILGI)
VALUES
	('Açıklama', 'Extra Bilgi')

GO

INSERT INTO TEST_TABLO_2 (ACIKLAMA, EKSTRA_BILGI) VALUES ('DENEME', 'TEST1')
INSERT INTO TEST_TABLO_2 (ACIKLAMA, EKSTRA_BILGI) VALUES ('DENEME', 'TEST2')
INSERT INTO TEST_TABLO_2 (ACIKLAMA, EKSTRA_BILGI) VALUES ('DENEME', 'TEST3')
INSERT INTO TEST_TABLO_2 (ACIKLAMA, EKSTRA_BILGI) VALUES ('DENEME', 'TEST4')

INSERT INTO TEST_TABLO_1 (ACIKLAMA, BILGI) VALUES ('DENEME', 'TEST1')

SELECT @@IDENTITY
UNION ALL
SELECT SCOPE_IDENTITY()
UNION ALL
SELECT IDENT_CURRENT('TEST_TABLO_1')

GO

DROP TRIGGER TRG_TEST
DROP TABLE TEST_TABLO_1
DROP TABLE TEST_TABLO_2

Sorgunun çıktısı;

IDENTITY_SCOPE_IDENTITY_IDENT_CURRENT

Gördüğünüz gibi, SELECT @@IDENTITY çalışan Trigger’dan etkilenerek yanlış sonucu döndürmüştür.

TEST_TABLO_2‘ye ilk eklediğimiz kayıtta, identity olarak 5 aldık.

SELECT SCOPE_IDENTITY() ise, doğru değer (1) döndürdü.

Sql Server CSV (Comma Seperated Value) çıktı üretme

Özellikle katalog tablolarının CSV çıktılarına sıklıkla ihtiyaç duyarız. Aşağıdaki sql script’ini kullanarak, siz de tablolarınızdan CSV çıktı alabilirsiniz.

Öncelikle tablomuzun orjinal haline bakalım;

SELECT Name
FROM HumanResources.Shift WITH (NOLOCK)

sql-csv-output_1

Şimdi öyle bir sql sorgusu yazacağız ki, çıktımız şu şekilde olacak;

Day, Evening, Night

SELECT
	SUBSTRING((
		SELECT ', ' + Name
		FROM HumanResources.Shift WITH (NOLOCK)
		FOR XML PATH('')
	), 3, 8000) AS CSV

Sorguyu FOR XML anahtar kelimeleri ile çalıştırdığımıza ve PATH olarak ” (boş string) verdiğimize dikkat edin.

SELECT ', ' + Name
FROM HumanResources.Shift WITH (NOLOCK)
FOR XML PATH('')

Böylece aşağıdaki sonucu elde etmiş olduk;

sql-csv-output_2

Son olarak, sql sorgusunu SUBSTRING fonksiyonu içerisine koyduk, böylece baştaki virgül ve boşluk karakterlerinden (“, “) kurtulmuş olduk.

sql-csv-output_3

Sql Server ServerProperty Fonksiyonu

Sql Server’ın çalıştığı sunucu ile ilgili özellik bilgilerine sorgu ile erişmek istediğimizde kullanabileceğimiz bir fonksiyon var;

SERVERPROPERTY ( propertyname )

Örnek;

SELECT
	SERVERPROPERTY('edition') AS SURUM,
	SERVERPROPERTY('productlevel') AS SEVIYE,
	SERVERPROPERTY('productversion') AS VERSIYON,
	SERVERPROPERTY('servername') AS SUNUCU_ADI

SERVERPROPERTY fonksiyonunun alabileceği tüm propertyname parametreleri ve açıklamaları için şuradaki MSDN sayfasına bakınız.

DataTable ve DataReader nesnelerini yarıştıralım

.Net ortamında veriye erişim modeli olarak kullanabileceğimiz iki seçenek vardır; Bağlantılı (Connected) ve Bağlantısız (Disconnected) Ortam.

  • Bağlantılı veri erişim modelinde, veriye erişmek için DataReader classını,
  • Bağlantısız veri erişim modelinde ise, genellikle DataTable classını kullanırız.

Bu yazımda, bu iki class’ı benzer şartlar altında yarıştıracağız ve hangisinin veriyi daha hızlı getirdiğine karar vereceğiz.

DataTable_vs_DataReader

Projenin kaynak kodlarını buradan download edebilirsiniz.

Kaynak kodlara baktığınızda görebileceğiniz gibi, proje tek form’dan oluşuyor. Formun Load event’inde, AdventureWorks2008R2 veritabanına bağlantı açılıyor ve PR_TABLO_LISTESI procedure’ü çalıştırılıyor.

PR_TABLO_LISTESI procedure’ünün kodları;

CREATE PROCEDURE PR_TABLO_LISTESI
AS
DECLARE @T TABLE (TABLO_ADI VARCHAR(100), SATIR_SAYISI INT)

INSERT INTO @T
EXEC sp_msForEachTable 'SELECT ''?'', COUNT(*) FROM ? WITH (NOLOCK)'

SELECT * FROM @T ORDER BY SATIR_SAYISI DESC

Gördüğünüz gibi, procedure’ün yaptığı çok fazla birşey yok. Pek fazla bilinmeyen ve dökümante edilmemiş sp_msForEachTable sistem prosedür’ünü kullanarak veritabanında bulunan her tablonun ismini ve satır sayısını döndürüyor.

Bu sistem prosedür’ünün nasıl kullanıldığını başka bir yazıda anlatmayı planlıyorum. (Eminim BilgeAdam’daki öğrencilerim bu prosedür’ü hatırlayacaklardır)

Form’un Load eventinin devamında, prosedür’den dönen liste (tablo isimleri ve satır sayıları) lvTablolar ismindeki ListView component’ine dolduruluyor.

cmbTekrarAdet isimli combobox’da yer alan (5 Adet, 10 Adet, 20 Adet) elemanlarından varsayılan olarak 10 Adet elemanı seçili olarak geliyor. Bu combobox, testin peşpeşe kaç defa tekrar edeceğini belirliyor. Böylece bilgisayardaki anlık performans değişikliklerine karşı önlem almış oluyoruz.

Yarış Başlasın Butonunun Click event’inde, yeni bir Thread nesnesini YarisBaslasin() methodunu çalıştıracak şekilde oluşturuyoruz ve başlatıyoruz.

YarisBaslasin() methodunu Arayüz’den (User Interface : UI) ayrı bir thread’den başlatarak, test süresince formda oluşacak kilitlenmeleri önlemiş olduk.

Method’un içerisinde DataTableHesapla() ve DataReaderHesapla() methodları çağırılıyor.

Bu methodlarda TekrarAdet defa (cmbTekrarAdet kontrolünden geliyor) SqlConnection açılıyor, ListView’da seçili tabloya SELECT çekiliyor ve dönen kayıtların üzerinde tek tek geziliyor.

Son olarak, DataTable ve DataReader nesnelerinde bu işlemlerin ne kadar sürdüğü karşılaştırılıyor ve sonuç ekranın altındaki bir label’da gösteriliyor.

Süre ölçmek, ADO.NET Connected ve Disconnected Environment’ı karşılaştırmak için tek başına kullanılacak bir yöntem değil. Fakat en azından bir fikir verebilir.

Sql Server 2008′de sıkıştırılmış yedek alma (compressed backup)

17 Kasım 2009 8 yorum

Sql Server 2008 ile birlikte gelen güzel bir yenilikten bahsetmek istiyorum, backup sırasında sıkıştırma (backup with compression).

Bu özelliği test etmek için, Sql Server 2008 R2 kurulu makinama AdventureWorks 2008R2 veritabanını yükledim.

Yükleme işleminden hemen sonra, şu sql cümlesi ile veritabanının backup’ını aldım;

BACKUP DATABASE
  AdventureWorks2008R2
TO DISK = 'C:\EnginPOLAT\AdventureWorks2008R2_Backup.bak'
WITH
  NOFORMAT,
  INIT,
  SKIP,
  NOREWIND,
  NOUNLOAD,
  STATS = 10

Karşılaştırma yapabilmek ve COMPRESSION anahtar kelimesini denemek için, bir de şu sql cümlesi ile yedek aldım;

BACKUP DATABASE
  AdventureWorks2008R2
TO DISK = 'C:\EnginPOLAT\AdventureWorks2008R2_Backup.bak'
WITH
  COMPRESSION,
  NOFORMAT,
  INIT,
  SKIP,
  NOREWIND,
  NOUNLOAD,
  STATS = 10

Gördüğünüz gibi, sıkıştırma özelliğini kullanmak için, backup script’inin options parçasına (WITH anahtar kelimesinden sonra gelen kısım), COMPRESSION anahtar kelimesini eklemek yeterli.

Şimdi gelelim karşılaştırmalara;

Orjinal boyut : 200.192 KB (Data) + 38.912 KB (Log)

Backup işlemi (Normal) sonucu oluşan dosya : 186.461 KB

Backup işlemi (Compression) sonucu oluşan dosya : 44.507 KB

Normal backup’a göre sıkıştırma oranı : %77

Backup alma süreleri açısından karşılaştırma,

Backup işlemi (Normal) : 7.505 saniye (24.018 MB / saniye)

Backup işlemi (Compression) : 4.521 saniye (39.862 MB / saniye)

Hız artışı : %40

Ne yazık ki, CPU kullanım oranlarını ölçemedim. Eğer ölçebilen varsa, yorumlarınızı duymak isterim.

MSDN’de yeralan şu sayfada yazdığına göre, backup işlemine compression eklemek, CPU kullanımında önemli bir artışa yol açarmış.

Varsayılan olarak alınacak tüm backup’larda sıkıştırma özelliğini açmak istersek;

EXEC sp_configure 'backup compression default', '1';
RECONFIGURE WITH OVERRIDE

script’ini çalıştırmak yeterli.

Kaynak : Technet, MSDN

SQL Server’da o an çalışan sorguları listelemek

Merhaba ilk yazımda SQL Server’da o anda çalışan sorguların nasıl listeleneceğini göstereceğim.

Bunu yapabilmek için sys.dm_exec_requests view’una sorgu çekmek lazım.

SELECT
    db.name,
    er.session_id,
    er.transaction_id,
    er.start_time,
    er.status,
    er.command,
    er.wait_time
FROM
    sys.dm_exec_requests AS er
    JOIN sys.sysdatabases AS db ON er.database_id = db.dbid
WHERE
    er.status = 'running'

Kaynak : sys.dm_exec_requests DMV (Dynamic Management View)

Kaynak : DBALink , Brad Mc Gehee