Miuul İnceleme

Trigram ile SQL Server'da Aşırı Hızlı Text Arama

Trigram yöntemini kullanarak SQL Server üzerinde bir database'de text arama işlemini anlatıyorum.


Source: Dimitris Ladopoulos

Merhaba,

Bu makalede trigram yöntemini kullanarak SQL Server üzerinde bir database de text arama işlemini anlatıyor olacağız.

Temel kavramlara girmeden önce şöyle bir senaryo üzerinden ilerleyelim. Alternatif yöntemlere bir göz atalım ve akabinde neden trigram kullandığımızı konuşalım.

Elimizde bir müşteri listemiz var. Bu veri 20 milyon satır içeriyor. Belki kafa karışıklığı olabilir diye en baştan yazayım. Buradaki verilerin hiçbiri gerçek veri olmayıp rastgele isim ve soyisimlerden türetilen 'fake' verilerdir. Nasıl oluşturulduğunu öğrenmek için bu makaleye bakabilirsiniz.



Customers tablomuzda görüldüğü gibi TCNUMBER alanı var.

Bizim amacımız burada TC kimlik numarası içinde geçen herhangi bir stringi getirmek. Burada aklımız gelen ilk arama şekli wildcard kullanmak. Yani like ile arama gerçekleştirmek.

İçinde 4248373 paterni geçen TC Kimlik numaralarını bulmak için sorgumuzu aşağıdaki gibi çalıştırıyoruz.

SET STATISTICS IO ON
SET STATISTICS TIME ON
SELECT * FROM CUSTOMERS WHERE TCNUMBER LIKE 'B48373%' 

Yaklaşık 4 saniyede geldi ve 597.547 adet page okudu.  Her bir page 8 KB’tan oluşuyor.

Bu da 597547*8KB/1024=4,6 GB a tekabül ediyor. Yani 8 satırlık bir sonuç döndüren bir sorgu 4.6 GB’lık bir veriyi okuyor. Bu okuduğu verileri byte byte karşılaştırmak için harcadığı CPU kaynağını söylemiyorum bile. Burada aynı anda sorgu çeken sadece bir kişiden bahsediyoruz.

Peki aynı anda 10 kişi bu işlemi gerçekleştirir ise ne olur ona bakalım. Bunun için ben basit bir uygulama yazdım ve rastgele numaraları like ile TCNumber sütununda arıyoruz. Elde ettiğimiz sonuç ise aşağıdaki gibi. Ortalama 25 saniye civarında.

Bu işlemler gerçekleşirken SQL Server sunucunun CPU durumu da tavan yapmış durumda.

Non-Clustered Index Kullanmak

Bu yavaşlık sorununu çözmek için ilk akla gelen konu index konusu. Zira biz biliyoruz ki index sorgu performansı için en önemli konu.

TCNumber alanına göre sisteme bir index koyalım.

CREATE INDEX IX1_TCNUMBER ON CUSTOMERS (TCNUMBER)

Şimdi sorgumuzu tekrar çekelim.

SQL Server özellikle koyduğumuz indexi kullansın diye buraya with hintini ekliyorum. Normalde SQL zaten bu indexi kullanır ama biz işimizi garantiye alalım.

SET STATISTICS IO ON
SET STATISTICS TIME ON
SELECT * FROM CUSTOMERS1 WITH (INDEX=IX1_TCNUMBER) WHERE  TCNUMBER LIKE 'B48373%'

Görüldüğü gibi değişen pek bir şey olmadı gibi. Bunun sebebi aslında oldukça açık. Zira başında ve sonunda % karakteri olan aramalarda index bir işe yaramaz. Çünkü belli bir sırada değildir. Neticede içinde herhangi bir yerde geçen bir kelimeyi arıyoruz.

Oysa başında % olmadan bir arama yapmayı deneseydik. Elde edeceğimiz sonuç oldukça başarılı olacaktı. Aşağıdaki resimde görüldüğü gibi belli bir formatta “ile başlar” şeklinde yaptığımız bir arama işlemi indexi kullandı ve toplamda 18 page okuyarak 0 ms de sorguyu getirdi. Bu ne demek?

Sorgunun 52.374/18=2.900 kat yani yaklaşık 3.000 kat daha hızlı çalışması demek. Ama ne yazık ki biz %% ile içinde geçen bir kelimeyi bulmak istiyoruz. Yani Nonclustered index işe yaramadı.

ColumnStore Index Eklemek

SQL Server’da bir başka index yöntemi de Column store index. Column store index kolonun kendisini indexleyen bir yapı ve bu tarz uygulamalar için çözüm olabilir. O zaman hemen bir column store index ekleyelim.

CREATE NONCLUSTERED COLUMNSTORE INDEX IX2_CS_TCNUMBER ON [dbo].[CUSTOMERS]
(
      [TCNUMBER]
)

Şimdi sorgumuzu tekrar çalıştıralım. Bu kez 3.8 saniye 3 saniyeye inmiş durumda. Okuma sayısı da 52.000’den 44.300’e inmiş durumda.  Yani sorunumuz yine çözülmedi.

Full Text Search Kullanmak

Derdimiz text arama olduğu için burada ilk akla gelen konulardan biri de full text search işlemi olabilir. Gelin onu da deneyelim. Bunun için önce bu tablo üzerinde fulltext tanımlamamız gerekiyor.

Burada özellikle TCNumber ile birlikte AddresText alanını da Fulltext e dahil ediyorum. Bunun sebebini açıklayacağım.




Fulltext i tanımladık. Artık bir sorgu çekebiliriz. Fulltext konusunu iyi anlamak için önce ADDRESSTEXT alanından bir arama gerçekleştirmek istiyorum.

Örneğin adres alanı içinde “DEĞİRMENDERE” geçen kayıtları arayalım.

Sorgumuz geldi. Şimdi de kaynak kullanımına bakalım. Görüldüğü gibi oldukça fazla bir kaynak kullanımı söz konusu. 594.150 adet page okumuş ki her biri 8KB. Ayrıca yaklaşık 17 saniye sürmüş. Bu sorgumuzdan yaklaşık 12.000 satır kayıt döndü. Adres gibi bir alanın içinde like ile bir kelime aramak TCNumber alanında aramaya benzemiyor. Sistemi oldukça yoruyor.

SET STATISTICS IO ON
SET STATISTICS TIME ON
SELECT ADDRESSTEXT,* FROM CUSTOMERS
WHERE ADDRESSTEXT LIKE '�ĞİRMENDERE%'

Şimdi de aynı işlemi FullText  search ile yapalım.

SET STATISTICS IO ON
SET STATISTICS TIME ON
SELECT ADDRESSTEXT,* FROM CUSTOMERS
WHERE  CONTAINS(ADDRESSTEXT, '"DEĞİRMENDERE"')

Sorgumuz geldi. Şimdi değerlerine bakalım. Bu kez değerlerimiz oldukça iyi. Okuma sayısı 42.064 olmuş. Süre ise 451 ms. Çok iyi rakam. Sonuçta 20 milyon satırlı bir tablo içinde text bir alanın herhangi bir yerinde geçebilecek bir “DEĞİRMENDERE” kelimesini aradık ve hızlı geldi. Toplamda 12.037 satır geldi.

Hızlı geldi. Zira fulltext search kelimeleri indexliyor. Yani kelimenin tamamını yazdığımızda ya da “DEĞİRME*” gibi bir kısmını yazıp “ile başlar“ şeklinde gönderdiğimizde çok hızlı çalışıyor. Şimdi “DEĞİRMEN*” şeklinde kullanalım.

Bu kez 68.000 satır geldi. Gördüğünüz gibi içinde “DEĞİRM” geçen bütün adresleri getirdi.

SET STATISTICS IO ON
SET STATISTICS TIME ON
SELECT ADDRESSTEXT,* FROM CUSTOMERS
WHERE  CONTAINS(ADDRESSTEXT, '"DEĞİRMEN*"')

Şimdi değerlere bir bakalım. 20 milyon satır. İçinde adres verisinin bulunduğu bir kolonda biz “DEĞİRMEN” ile başlayan kelimeleri arıyoruz. Süre 777 ms ve 272.544 page okunmuş. Burada dönen sonuç 68.000 satır olduğu için bu kadar page okuma işlemi normal.

Sonuç: Fulltext search işe yarıyor.

Ama bizim derdimiz neydi? İle başlar değil içerir şeklinde arama yapmak.

O zaman “*EĞİRMEN*” kelimesini arayalım.

Görüldüğü gibi kayıt gelmedi. Çünkü EĞİRMEN diye bir kelime yok. Başına joker karakter koysam da gelmedi.

Aynısını TCNUMBER alanı için uygulayalım. Öyle ya biz bu alana da full text index eklemiştik. TC Kimlik numarası 9146823 ile başlayanları getirmek istediğimizde sorgu doğru ve hızlı çalışıyor.

SET STATISTICS IO ON
SET STATISTICS TIME ON
SELECT TCNUMBER,* FROM CUSTOMERS
WHERE  CONTAINS(TCNUMBER, '"9146823*"') 

Hem de oldukça hızlı.

Aranan kelimenin başına ve sonuna * işareti koyduğumda ise yine sadece kelimenin başlangıcı aranan kelime olanları getiriyor. Yani “146823 ile başlar” olanları getiriyor. İçinde “146823” geçenleri getirmiyor.

Sonuç: Fulltext arama da işimizi görmedi.

Trigram Kullanımı

SQL Server ve diğer veritabanı yönetim sistemleri veriyi dikeyde aramak için tasarlanmıştır. Yani satırlar üzerinde doğru optimize edilirse satır sayısı ne kadar olursa olsun performanslı bir şekilde arama işlemi gerçekleşir. Ancak %% kalıbı ile aradığımızda sistem yatayda bir arama gerçekleştirir.

Örneğin 14682321186 ifadesinin içinde 82321 ifadesini ararken sürekli bir kaydırma durumu ile karşılaştırma işlemi yapılır.

Gördüğünüz gibi  her seferinde bir kaydırma işlemi ile arama gerçekleşiyor. Üstelik bu işlem 1 satırda yapılan işlem. Bunun gibi 20 milyon satır var. Bu durumda tablodaki satır sayısı, aranan stringin uzunluğu, arama yapılan kolonun uzunluğu veritipi gibi etkenler ile oldukça verimsiz bir arama şekli karşımıza çıkıyor. İşte bu durum like %% ile aramanın ne kadar verimsiz olduğunu açıklıyor.

Biz ne demiştik? Veritabanları dikeyde çalışmak için tasarlanmıştır. Doğru index ve BiTree algoritması ile çok hızlı şekilde arama yapabiliriz. Ama verimiz yan yana tren vagonu dizilen harfler.  Yani yatay veri. O zaman bu yatay veriyi dikey hale getirebilirsek bizim işimiz çözülecek demektir.

Bu noktada Trigram dediğimiz yapı ile bu işlemi gerçekleştirebiliriz. Trigram, bir kelimeyi 3’erli şekilde parçalayarak satırlara ekleme işlemine verdiğimiz isim.

Örneğin: 14682321186 kelimesini ele alalım. Bu kelimenin trigramı aşağıdaki gibi 9 satırdan oluşur.

Bu trigram içerisinde arama yapabilmek için arama yapacağımız kelimeyi de trigram olarak parçalamamız gerekiyor.

Arama yapacağımız kelime 82321. Şimdi bu kelimenin trigramlarına bakalım. Yani 3 er karakter ile parçalayalım.

Görüldüğü gibi burada 3 farklı kelime karşımıza çıktı.

Sırada artık satır satır 823,232 ve 321 kelimelerini 9 satırdan oluşan tablo içinde aratmak kalıyor. Bu tabloya da bir index eklersek bu bildiğimiz dikey arama. Hani bizim iyi olduğumuz taraf.

Aslında bu teknolojinin adı Ngram. Yani burada N sayısını biz belirliyoruz. Örneğin Bigram ikili olarak parçalama, Trigram ise üçlü olarak parçalama. En çok tercih edilen Trigram.

Bu kadar teorik bilgiden sonra gelin şimdi bu işi SQL tarafında nasıl yapıyoruz ona bir gözatalım.


SQL Server Üzerinde Trigram

Öncelikle şunu söylemeliyim ki, SQL Server ve TSQL’de hazır bir trigram yapısı yok. PosgreSQL’de bu yapı bir eklenti ile hazır halde geliyor. Biz burada kendi trigram yapımızı kendimiz oluşturacağız.

Her şeyden önce bizim herhangi bir string ifadeyi Trigram tablosuna çevirecek bir table valued function a ihtiyacımız var. Aşağıda bu fonksiyonun kodlarını paylaşıyorum. Bu fonksiyonda ben hızlı olsun diye maximum 16 adet trigram ile sınırladım. Çünkü TC kimlik numarası zaten 9 tane trigram çıkarıyor. Bu sayı duruma göre bu değer değiştirilebilir.
 

CREATE function dbo.strToTrigram(@String varchar(100))
Returns Table
As
Return
(
Select substring(@string,v,3) Trigram,T.v  Seq
            from
            (
                values
                    (1),(2),( 3),(4),(5),(6),(7),(8),
                    (9),(10),(11),(12),(13),(14),(15),(16)
            ) as T (v)
                  where LEN(substring(@string,v,3))='3'
)

 Şimdi de bu fonksiyonun kullanımını görelim.

SELECT * FROM dbo.strToTrigram('14682321186')

Burada Trigram alanı parçalanmış değeri getirirken Seq alanı ise bu trigramın string ifade içerisindeki sıra numarasını getirmekte. Bu bize sorgularımızda çok yardımcı olacak.

Şimdi artık sıra geldi customers tablosundaki her bir satırın trigramını çıkarmaya. Bu ne demek? 20 milyon satır*9=180 milyon satırlık bir trigram. Burada tc kimlik numarası uzunluğu sabit olduğu için bu değeri tahmin etmek kolay.

Şimdi bir tablo oluşturalım. Tablomuzun adı CUSTOMER_TCNR_TRIGRAM

ID: Otomatik artan bir integer alan. Tablomuzun primary key’i.
ROWID: Customers tablosundaki ID alanının referans numarası.,
TRIGRAM: Parçalanan trigram değeri.
SEQ: Trigramın sıra numarası.

Şimdi sıra geldi bu 20 milyon satırlık tablonun trigramını çıkarıp CUSTOMER_TCNR_TRIGRAM tablosuna insert etmeye.

Burada 20 milyon satırı tek seferde aktarmak yerine 1’er milyon aktarmak daha kolay olacaktır.

Aşağıdaki kod bloğu bu işlemi 20 kere çalışan bir döngü ve her seferinde 1 milyon satırlık müşteri kaydının trigramlarına ayrılarak CUSTOMER_TCNR_TRIGRAM tablosuna insert edilmesi işlemini gerçekleştiriyor.

DECLARE @MAXID AS INT
DECLARE @I AS INT=0

WHILE @I<20>
BEGIN

SELECT @MAXID=MAX(ROWID)   FROM CUSTOMER_TCNR_TRIGRAM
SET @MAXID=ISNULL(@MAXID,1)
      INSERT INTO CUSTOMER_TCNR_TRIGRAM  (ROWID,TRIGRAM,SEQ)
            SELECT   C.ID,T.Trigram,T.seq FROM CUSTOMERS C
                  CROSS APPLY (SELECT * FROM dbo.strToTrigram(C.TCNUMBER)) t
            WHERE C.ID BETWEEN @MAXID AND @MAXID+1000000 AND t.seq<>''
            ORDER BY C.ID,t.seq
      SET @[email protected]+1
END

Bu sorgunun sonucunda bir satır için satırın değerine ve trigram değerlerine bakacak olursak, bir satırdaki TCNumber kolonu için 9 satır trigram oluştuğunu görüyoruz.

Toplam rakama bakacak olursak, toplamda 20 milyon satırlık bir tablo için 180 milyonluk bir trigram oluşmuş durumda.

Trigram ile Arama

Şimdi artık arama sorgumuzu yazabiliriz. Normalde Posgresql veritabanında trigram ile alakalı hazır komutlar ve hazır bir eklenti var. Ancak gördüğüm kadarı ile SQL Server’da böyle bir eklenti ya da bir komut yok. Bu nedenle şimdilik benim yazdığım bir algoritmayı kullanacağız. Bu algoritmayı tamamen ben yazdım. Literatürde var mıdır bilmiyorum. Açıkçası çok araştırmadıma ama dediğim gibi özgün bir çalışma.

Tabi hızlı arama için trigram tablosunda bir takım indexlere ihtiyacımız var. O indexlerin scriptlerini de burada paylaşıyorum.

ALTER TABLE [dbo].[CUSTOMER_TCNR_TRIGRAM ] ADD  CONSTRAINT [PK_TCNOTRIAGRAM]
PRIMARY KEY CLUSTERED
(
      [ID] ASC
)
CREATE NONCLUSTERED INDEX [IX1] ON [dbo].[CUSTOMER_TCNR_TRIGRAM ]
(
      [TRIGRAM] ASC
)
INCLUDE([ROWID],[SEQ])
CREATE NONCLUSTERED INDEX [IX2] ON [dbo].[CUSTOMER_TCNR_TRIGRAM ]
(
      [ROWID] ASC
)

Arama işlemini gerçekleştiren procedure ümüz dinamik bir sql cümlesi oluşturuyor ve biz oluşan bu sql cümlesini çalıştırıyoruz.

Önce procedürümüzü bir çalıştıralım ve sonuca bakalım. Aradığımız patern '4248373' yani TCKimlik numarası içinde bu kalıbın geçtiği kayıtları bulmaya çalışacağız.

SET STATISTICS IO ON
EXEC SEARCH_TCNUMBER '4248373'

Arama sonucunca 93 satır kayıt geldi ve 64 ms sürdü. Makalenin başında bu sorguyu like ile çağırdığımızda yaklaşık 3.2 saniye sürmüştü ve 41.000 page okumuştu. Bizim sorgumuzda ise 64 ms ve toplamda yaklaşık 4944 page okuyor. 

Şimdi stored procedure’ümüzü paylaşalım.

 

create PROC [dbo].[SEARCH_TCNUMBER]  
@STRINGID AS VARCHAR(100)
AS
DECLARE @DATE AS DATETIME
set @DATE =GETDATE()

 

SET @STRINGID=REPLACE(@STRINGID,'%','')
DECLARE @SQL AS NVARCHAR(MAX)=''
DECLARE @LASTSQL AS NVARCHAR(MAX)=''
DECLARE @STR AS VARCHAR(100)
DECLARE @I AS INT=1
DECLARE @COUNTER AS INT=1
DECLARE CRS CURSOR FOR SELECT TRIM(trigram) FROM dbo.strToTrigram(@STRINGID) ORDER BY SEQ
OPEN CRS
FETCH NEXT FROM CRS INTO @STR
WHILE @@FETCH_STATUS=0
BEGIN
      IF @I=1
      BEGIN
            SET @SQL='SELECT ROWID INTO #T FROM CUSTOMER_TCNR_TRIGRAM T1 '
            SET @[email protected]+CHAR(13)+'WHERE TrIgram LIKE '''[email protected]+''''
            SET @[email protected]+' AND T1.ROWID IN '
            SET @[email protected]+CHAR(13)+REPLICATE(' ',3)+'('
      END

      ELSE
      BEGIN
      IF LEN(@STR)=3
            BEGIN  --SET @[email protected]+'%'
            SET @[email protected]+1
                  SET @LASTSQL=''
                  SET @[email protected]+CHAR(13)+REPLICATE(' ',@COUNTER*3)+'SELECT T'+CONVERT(VARCHAR,@COUNTER) +'.ROWID FROM CUSTOMER_TCNR_TRIGRAM T'+CONVERT(VARCHAR,@COUNTER)
                  SET @[email protected]+' WHERE T'+CONVERT(VARCHAR,@COUNTER) +'.SEQ>T'+CONVERT(VARCHAR,@COUNTER-1) +'.SEQ AND TrIgram LIKE '''[email protected]+''''
                  SET @[email protected]+' AND T'+CONVERT(VARCHAR,@COUNTER) +'.ROWID IN '
                  SET @[email protected]+CHAR(13)+REPLICATE(' ',@COUNTER*3)+'('
                  SET @[email protected]+CHAR(13)[email protected]
            END
      END
      SET @[email protected]+1
      FETCH NEXT FROM CRS INTO @STR
END

 

DECLARE @LASTSQLTMP AS NVARCHAR(MAX)[email protected]
DECLARE @POS AS INT=CHARINDEX('AND',@LASTSQLTMP)
SET @LASTSQLTMP=SUBSTRING(@LASTSQLTMP,1,@POS-1)
 SET @SQL=REPLACE(@SQL,@LASTSQL,@LASTSQLTMP)

 

SET @I=1
WHILE @I<@COUNTER
BEGIN
      SET @[email protected]+CHAR(13)+REPLICATE(' ',(@COUNTER-(@I+1))*3)+')'
SET @[email protected]+1 
END

 

SET @[email protected]+';'
SET @[email protected]+CHAR(13)+'SELECT'
SET @[email protected]+CHAR(13)+'NAME_+ '' ''+SURNAME AS NAMESURNAME,TELNR'
SET @[email protected]+CHAR(13)+'FROM CUSTOMERS WHERE ID IN (SELECT ROWID FROM #T)'
SET @[email protected]+CHAR(13)+'DROP TABLE #T'
-- SET @[email protected]+')'

 

PRINT @SQL
CLOSE CRS
DEALLOCATE CRS
 --SELECT @SQL
 EXEC SP_EXECUTESQL @SQL
DECLARE @DIFF AS INT
SET @DIFF=DATEDIFF(MILLISECOND,@DATE,GETDATE())
DECLARE @SECOND AS INT
DECLARE @MS AS [email protected]
SET @SECOND [email protected]/1000
SET @[email protected]@SECOND*1000
DECLARE @RESULT AS VARCHAR(100)
IF (@SECOND)<10>       SET @RESULT='00:00:0'+CONVERT(VARCHAR,@SECOND)
ELSE
SET @RESULT='00:00:'+CONVERT(VARCHAR,@SECOND)
IF (@MS)<10>       SET @[email protected]+' 00'+CONVERT(VARCHAR,@MS)
IF (@MS)BETWEEN 10 AND 99
      SET @[email protected]+' 0'+CONVERT(VARCHAR,@MS)
IF (@MS)BETWEEN 100 AND 999
      SET @[email protected]+' '+CONVERT(VARCHAR,@MS)
SELECT @RESULT AS RESULT, (@SECOND*1000)[email protected] AS MS

 

Procedure’ün dinamik bir sql cümlesi oluşturduğunu söylemiştik. Oluşan sql cümlesi şu şekilde.

Bu sorguyu çalıştırdığımızda elde ettiğimiz sonuç da aynı. Burada ben bu sorguda neyin ne işe yaradığını anlatmak istemiyorum. Sorguyu doğrudan paylaşıyorum siz yorumlayın.

 

SELECT ROWID INTO #T FROM CUSTOMER_TCNR_TRIGRAM T1
WHERE TrIgram LIKE '424' AND T1.ROWID IN
   (
      SELECT T2.ROWID FROM CUSTOMER_TCNR_TRIGRAM T2 WHERE T2.SEQ>T1.SEQ AND TrIgram LIKE '248' AND T2.ROWID IN
      (
         SELECT T3.ROWID FROM CUSTOMER_TCNR_TRIGRAM T3 WHERE T3.SEQ>T2.SEQ AND TrIgram LIKE '483' AND T3.ROWID IN
         (
           SELECT T4.ROWID FROM CUSTOMER_TCNR_TRIGRAM T4 WHERE T4.SEQ>T3.SEQ AND TrIgram LIKE '837' AND T4.ROWID IN
            (
               SELECT T5.ROWID FROM CUSTOMER_TCNR_TRIGRAM T5 WHERE T5.SEQ>T4.SEQ
         )
      )
   )
);

SELECT
NAME_+ ' '+SURNAME AS NAMESURNAME,TELNR
FROM CUSTOMERS WHERE ID IN (SELECT ROWID FROM #T)
DROP TABLE #T

Şimdi de aynı anda birden fazla sorgu ile trigram arama algoritmamızı deneyelim. Bakalım Like’a göre ne kadar performans kazanmışız?

Görüldüğü gibi aynı anda 10 oturumdan rastgele arama gerçekleştiriliyor ve ortalama sorgu süresi 150-200 ms arasında değişiyor. Ne dersiniz? Çok iyi değil mi?

CPU kullanımına bakalım bir de. Gördüğünüz gibi % lerde. Yani gayet güzel bir değer. Like ile aradığımızda 99%’u görmüştük.
Şuraya yazının başında paylaştığımız ve like ile aradığımız halini de koyalım ve ne kadar performans kazandığımızı dünya gözüyle bir görelim.

Normal like ile aradığımızda elde ettiğimiz ortalama süre 20 saniye civarında. Şimdi siz söyleyin. 20 saniye nereeee, 150 ms nere?

Peki bir like araması için bu kadar zahmete değer mi? Buna siz karar verin. Eğer bu denli kritik bir uygulamanız varsa bence kesinlikle değer.

Peki Customers tablomuzda bir değişiklik, güncelleme, yeni ekleme olduğunda ne olacak? Bunun için de basit bir trigger yazarak tablodaki bir satırda bir değişiklik olduğunda trigram tablosuna otomatik olarak insert gerçekleştirebilirsiniz.

Son olarak burada kullandığım database’i buradan indirebilirsiniz.

Uzunca bir yazı oldu. Okuduğunuz için teşekkür eder, faydasının olduğunu ve beğendiğinizi ümit ederim.

Sağlıcakla..

Dengesiz Veri Seti Ne Zaman Problem Olur?

Nehir Günce Daşcı

Makine Öğrenmesinde Değişken Seçimi: Filtreleme Yöntemleri

Simge Erek

SQLSharp ile T-SQL’in Sınırlarını  Genişletin

Ömer Çolakoğlu
Deniz Güler

Elinize sağlık hocam çok verimli bir paylaşım olmuş. Merak ettiğim bir konuydu ve tamda üzerine geldi. DB'yi indiremedim yalnız, açılan klasörde herhangi bir dosya yok, kontrol edebilir misiniz rica etsem?

SON İNCELEMELER

GİRİŞ

Aşağıya kaydolduğunuz e-postayı girin. Şifrenizi sıfırlamanız için size bir bağlantı göndereceğiz.

Giriş Ekranına Dön
Şifre sıfırlama talimatları
adresine gönderildi.