SQL Dizinleri ve Bölümleri ile Darboğazları Çözme
Yayınlanan: 2022-03-11SQL Indexes Açıklamasının ilk dersinde, veriler belirli sütunların değerlerine göre sıralandığında SELECT sorgularının daha hızlı olduğunu öğrendik.
İkinci derste, B-tree indekslerinin temel yapısını ve sorgu yürütürken eriştiğimiz veri hacmini azaltmak için bunların nasıl kullanılacağını öğrendik. Ayrıca, birden çok tabloyu birleştiren sorguların nasıl uygulanacağını ve dizinlerin bu tür sorguları nasıl hızlandırabileceğini anladık.
Ayrıca SQL'de dizin kullanımının faydalı olduğu iki senaryoyu da vurguladık. Dizinler, sorgudaki tüm sütunları içeren dizinleri kapsadığında - WHERE koşulları, JOIN koşulları ve SELECT listesinden - ilgili tabloyu tamamen okumaktan kaçınırız. Alternatif olarak, dizinler, tablo boyutunun küçük bir kısmına erişilen veri bloklarının sayısını azalttığında yardımcı olabilir.
Aksi takdirde, bir dizinden okumaktan ve ilgili tablo satırlarına rastgele ileri geri atlamaktansa tüm tabloyu taramak daha verimlidir.
SQL Aralığı Sorguları
Dizinlerden yararlanabilen sorgular, tipik olarak, bir veya daha fazla sütunun alabileceği olası değerlerin aralığını önemli ölçüde azaltan koşulları içerir. Aralık sorguları, "A Sütununun değeri X ile Y arasında olmalıdır" gibi koşullara dayalı olarak verileri kısıtlar.
Buna iyi bir örnek, ikinci dersteki Alıştırma 4'teki sorgudur:
SELECT c.ClientName FROM Reservations r JOIN Clients c ON r.ClientID = c.ClientID WHERE r.DateFrom BETWEEN ( TO_DATE('2020-08-13', 'YYYY-MM-DD') AND TO_DATE('2020-08-14', 'YYYY-MM-DD') ) AND r.HotelID = 3; Burada iki aralığımız var. İlki, 13 Ağustos 2020 ile 14 Ağustos 2020 arasındaki tarih aralığıdır. İkincisi, mümkün olan en küçük sayısal aralıktır. Koşul, r.HotelID BETWEEN 3 AND 3 eşdeğerdir.
Alıştırma 1: Dönemler (Tarih ve Zaman Aralığı Sorguları)
Reservations tablosuna CheckInTime isimli bir kolon ekleyelim. Bu e-tabloda örnek verileri görebilirsiniz. Hem CheckInTime hem de ClientId kapsayan tek bir dizin olduğuna dikkat edin.
15 Ağustos 2020'de giriş yapan müşterilerin adlarını döndürecek bir sorgu yazın.
Deneyimsiz SQL geliştiricileri genellikle aşağıdaki sorguyu yazar:
SELECT c.ClientName FROM Reservations r JOIN Clients c ON r.ClientID = c.ClientID WHERE TO_DATE(r.CheckInTime, 'YYYY-MM-DD') = '2020-08-15';Sorgu yürütmenin şöyle görüneceğini varsayıyorlar:
Get first row from IX_CheckInTime_ClientID where TO_DATE(CheckInTime, 'YYYY-MM-DD') = '2020-08-15' While found and TO_DATE(CheckInTime, 'YYYY-MM-DD') = '2020-08-15' Fetch Clients.* where ClientID = IX_CheckInTime_ClientID.ClientID Write down Clients.ClientName Get next row from IX_CheckInTime_ClientID Sorun şu ki, bu yazının yazıldığı sırada tek bir RDBMS böyle bir yürütme planı oluşturamıyor. TO_DATE (Oracle sözdizimi), CheckInTime sütununun değerini dizine eklenmemiş bir şeye dönüştüren bir işlev olarak görürler. Bu nedenle, oluşturma eğiliminde oldukları yürütme planları şöyle görünür:
For each row from IX_CheckInTime_ClientID If TO_DATE(CheckInTime, 'YYYY-MM-DD') = '2020-08-15' then Fetch Clients.* where ClientID = IX_CheckInTime_ClientID.ClientID Write down Clients.ClientName Dizin satırı tablo satırından daha dar olduğundan, bunu yürütmek Reservations tablosundaki tüm satırları okumaktan daha hızlı olacaktır. Daha küçük bir satır, diskten daha az bloğa erişilmesi gerekeceği anlamına gelir.
Ancak ilk uygulama planının çok daha verimli olacağını biliyoruz. RDBMS'mizi bu yaklaşımı kullanmaya ikna etmek için sorguyu yeniden yazmamız gerekiyor:
SELECT c.ClientName FROM Reservations r JOIN Clients c ON r.ClientID = c.ClientID WHERE r.CheckInTime >= TO_DATE('2020-08-15 00:00:00', 'YYYY-MM-DD HH:MI:SS') AND r.CheckInTime < TO_DATE('2020-08-16 00:00:00', 'YYYY-MM-DD HH:MI:SS'); Bu, her iyi RDBMS'nin anlayacağı uygun bir aralık sorgusudur. RDBMS'miz, CheckInTime değerinin - ondan türetilen bir şey değil - iyi tanımlanmış aralığa ait olduğu Reservations tablosundan veri istediğimizi anlıyor. Oluşturduğu yürütme planı daha çok şöyle olurdu:
Get first row from IX_CheckInTime_ClientID where CheckInTime >= '2020-08-15 00:00:00' While found and CheckInTime < '2020-08-16 00:00:00' Fetch Clients.* where ClientID = IX_CheckInTime_ClientID.ClientID Write down Clients.ClientName Get next row from IX_CheckInTime_ClientIDGerçekten istediğimiz şey bu: sadece indeksin kendisinden değil, aynı zamanda sıralanmış olduğu gerçeğinden de yararlanmak.
Alıştırma 2: Başlangıçta Bir Joker Karakterle LIKE
Bu sefer dedektifimiz şüpheli hakkında belirsiz bilgilerle otele gelir: Sadece soyadının “-son” ile bitmesi. Dedektif, bu tür tüm konukların adlarını ve soyadlarını istiyor:
SELECT FirstName, LastName FROM Clients WHERE LastName LIKE '%son'; Clients tablosu ve LastName bir dizin için bu elektronik tabloyu kullanacağız. Sorgunun döndüreceği sonuçları yazın. Uygulayabileceğiniz farklı yaklaşımları düşünün.
Tablo Tarama Yaklaşımı
En basit strateji, tablodaki tüm verileri okumak ve soyadları “-son” ile biten misafirlerin adlarını yazmaktır:
For each row from Clients If LastName like '%son' then write down FirstName, LastNameBurada, tüm tabloyu sırayla okumamız gerekecek.
Dizin Kullanma
LastName sütunundaki dizinden yararlanmaya çalışalım. IX_LastName sayfasına gidin, verilen kriteri karşılayan tüm istemcileri bulmak için kullanın ve adlarını yazın.
Tablodaki tüm Anderson'ları, Robinson'ları ve Thompson'ları bulmak için dizinin tamamını okumanız gerektiği ortaya çıktı. Bu, tablo taraması kullanmaktan daha mı iyi? Dizinin tamamını okumanın yanı sıra, eşleşen her giriş için rowAddress değerini kullanarak tablodan ilgili satırı bulmanız ve ardından buradan FirstName yazmanız gerekiyordu:
For each row from IX_LastName If LastName like '%son' then Fetch Clients.* where RowAddress = IX_LastName.RowAddress Write down FirstName, LastNameTabloyu sırayla okumak bizim için daha basit ve hızlıydı. RDBMS'miz için, kriterleri karşılayan satırların yüzdesine bağlı olacaktır. Büyük bir tabloda sadece bir avuç Andersons, Robinsons ve Thompsons varsa, bir RDBMS bir eşleşme bulunduğunda tablodan birkaç blok okuması gerekse bile çok daha dar dizin girişlerinden daha az veri bloğu okuyacaktır. Aksi takdirde, tablo taraması daha az zaman alır.
Dizindeki verileri sıralamak, böyle bir sorgu ile herhangi bir yardım sağlamaz. Dizin satırının daha küçük boyutu yardımcı olabilir - ancak bazen.
Alıştırma 3: Sonunda Bir Joker Karakterle LIKE
Dedektifimiz bir daha geldiğinde, soyadları "Rob-" ile başlayan tüm müşterileri bulmamız gerekiyor.
SELECT FirstName, LastName FROM Clients WHERE LastName LIKE 'Rob%';Aynı elektronik tablodan sorguyla eşleşen verileri çıkarmaya çalışın.
Tablo tarama yaklaşımını kullandıysanız, IX_LastName dizininden tam olarak yararlanma fırsatını kaçırdınız. “Rob-” (Roberts) ile başlayan dizinden ilk girişi bulmak, sonraki satırları (hem Robertses hem de Robinsons) okumak ve LastName artık ölçütle eşleşmediğinde durmak çok daha hızlıdır:
Get first row from IX_LastName where LastName <= 'Rob' While found and LastName < 'Roc' Fetch Clients.* where rowAddress = IX_LastName.rowAddress Write down FirstName, LastName Get next from IX_LastNameBu durumda, ilk giriş için B-ağacı aramasından sonra, sadece kriteri karşılayan girişleri okuruz. Kriterlere uymayan bir isim okuduğumuz anda okumayı bırakıyoruz.
B Ağacı Ölçekleme Sorunlarını Ele Alma
Tipik olarak, yeni bir veritabanını dağıttığımızda, birkaç doldurulmuş arama tablosu ve boş işlem tabloları vardır. Sistem, özellikle tabloları normalleştirerek iyi veritabanı tasarımı uygulamalarına saygı duyuyorsak, başlangıçtan itibaren sorunsuz çalışır; birincil, yabancı ve benzersiz anahtarlar oluşturma; ve karşılık gelen dizinlerle yabancı anahtarları destekleme.
Birkaç ay veya yıl sonra, veri hacmi sistem ve veritabanı karmaşıklığını önemli ölçüde artırdığında, performans düşüşünü fark etmeye başlarız. Sistemin neden yavaşladığı ve bu konuda ne yapılması gerektiği konusunda görüşler ortaya çıkıyor.
Popüler görüş, genellikle veritabanının boyutunun birincil suçlu olduğu yönündedir. Çözüm, günlük olarak ihtiyacımız olmayan geçmiş verileri kaldırmak ve raporlama ve analitik için ayrı bir veritabanına yerleştirmek gibi görünüyor.
Önce ana varsayımı inceleyelim.
SQL Aralığı Sorguları: Yürütme Süresi Tablo Boyutuna Bağlı mı?
Tek bir tablodan tipik bir aralık sorgusu düşünün:
SELECT Column1, …, ColumnN FROM Table WHERE Column BETWEEN X AND Y; Column üzerinde bir dizin olduğunu varsayarsak, en uygun yürütme planı şudur:
Get first row from IX_Column where Column between X and Y While found and Column <= Y Fetch Table.* where rowAddress = IX_Column.rowAddress Write down Column1, …, ColumnN Get next row from IX_ColumnBu verileri döndürmek için bir RDBMS'nin okuması gereken blokları sayalım.
Get first row kısmı, ikinci derste tanıttığımız B-ağacı araması tarafından uygulanmaktadır. Okuması gereken blok sayısı B ağacının derinliğine eşittir. Bundan sonra, dizinin yaprak seviyesinden sonraki maddeleri okuruz.
OLTP sorgularında, tipik olarak tüm sonuçlar tek bir dizin bloğunda bulunur (bazen iki ancak nadiren daha fazla). Buna ek olarak, her bir dizin girişi için, adresine göre ilgili satırı bulmak için tablodaki bir bloğa erişimimiz vardır. Bazı tablo satırları önceden yüklediğimiz tablo bloğunun içinde olabilir, ancak tahmini basitleştirmek için her seferinde yeni bir blok yüklediğimizi varsayalım.
Yani formül:
B = D + 1 + R
B, okunan toplam blok sayısı, D, B ağacı derinliği ve R, sorgu tarafından döndürülen satır sayısıdır.
Tablodaki satır sayısına bağlı olan tek parametre B ağacı derinliği olan D'dir.
Hesaplamaları basitleştirmek ve bir noktaya değinmek için, 1000 dizin girişinin bir bloğa sığdığını varsayalım. Tabloda 1.000'den az satır olduğu sürece D = 1'dir. Ticari işlemleri tutan tablolar için bu, sistem dağıtımından sonraki ilk iş günü olabilir. Yakında, B ağacı derinliği artacak. Tabloda 1 milyondan az satır olduğu sürece indeks iki seviyeden oluşacaktır.
Yavaş veritabanı yanıt sürelerinden rahatsızsak ve bunun için veri hacmini suçluyorsak, işlem tablolarının genellikle yalnızca milyonlarca satıra sahip olduğunu unutmayın. Sadece 1 milyon satır iki seviyeli bir B-ağacı indeksine uyduğundan, derinlik en az üç olmalıdır. Tabloda 1 milyardan fazla satır olmadıkça derinlik dörde çıkmayacak. Şimdi daha kesin bir tahminimiz var:
B = 4 + R
R küçükse, B ağacı derinliğini ikiye düşürmek sorguyu önemli ölçüde hızlandırır. Birincil veya benzersiz bir anahtar değerine göre arama yaptığımızda, sistem %20'lik bir iyileştirme olan beş yerine dört blok okuyacaktır. Sorgu daha fazla satır döndürürse, iyileştirme fark edilmeyebilir. Sorun şu ki, birçok uygulama için veritabanında 1 milyondan az işlem tutarak gerekli iş operasyonlarını destekleyemeyebiliriz.

Dolayısıyla sonuç, tablo boyutunun önemli olmadığı gibi görünüyor; başka bir deyişle, geçmiş verileri taşımak zaman ve kaynak kaybıdır.
Ama o kadar hızlı değil: Bir B-ağacı indeksinin yapısı ve veri değişikliklerinin onu nasıl etkilediği hakkında daha fazla bilgi edelim.
B-ağacı Dizin Uygulama Ayrıntıları
İkinci dersteki B-ağacı indeksleri kapsamında, dengeli bir ağacın tüm seviyelerinin (fiziksel olarak) anahtar sütun değerlerine göre sıralandığını gördük. Ancak, bir öğeyi eklemek, güncellemek veya silmek istediğimizde, siparişi korumak için genellikle büyük miktarda veri taşımamız gerekir.
Dolu olan bir bloğun ortasına yerleştirdiğimizi varsayalım. Bloğu bölmemiz, verileri yeniden düzenlememiz ve hatta bazen mevcut olanı işaret eden başka bir B-ağacı seviyesindeki verileri güncellememiz gerekiyor.
Bu gibi durumları daha verimli hale getirmek için, her bir dizin öğesi, önceki ve sonraki satırlara yönelik işaretçiler içerir ve bu, onu çift bağlantılı hale getirir. Genel olarak ekleme için bu, yeni öğeleri bir öncekine mümkün olduğunca yakın yazmamız ve işaretçileri düzeltmemiz anlamına gelir.
Bir bloğu da bölmemiz gerektiğinde, önceki B-ağacı seviyesinde yeni bir öğe yazmalıyız. Bu sadece birkaç işaretçiyi daha düzeltme meselesidir - ağacın büyük kısımlarını yeniden yazmaya gerek yoktur. Bölmeden sonra, her iki veri bloğu da yaklaşık olarak yarı doludur. Diskte nerede boş alan olduğuna bağlı olarak, “komşu” bloklar fiziksel olarak oldukça uzak olabilir.
Bir süre sonra dizin parçalanması artar ve sorgu yürütme yavaşlaması fark edilir hale gelir. Sorguları tanımladığımız şekilde yürüten bir RDBMS ile, öğelerin sırası ve yakınlığı varsayımı giderek daha az doğru hale gelir ve çok daha fazla okumaya yol açar. En kötü durumda, tüm veri bloklarının yarısı boşken, sistem iki kat daha fazla blok okumak zorundadır.
B-ağacı Dizin Bakımı
Bunun tedavisi dizin birleştirmedir (veya "yeniden dizin oluşturma"). Her RDBMS, tüm bir dizini yeniden oluşturmak için bir özellik sağlar; yeniden indekslemeden sonra indeksler bir kez daha fiziksel olarak sıralanır.
Yeniden indeksleme, yüksek miktarda veri okuyup yazmasına rağmen oldukça hızlı bir işlemdir. Modern RDBMS'ler tipik olarak iki yeniden indeksleme modu sunar; daha hızlı olanı, işleme sırasında tabloların kilitlenmesini gerektirir. Her iki durumda da, yoğun olmayan saatlerde yeniden dizine eklenmesi tercih edilir. Aksi takdirde, işleme, veritabanı performansını yavaşlatabilir.
Geçmiş Verileri Silme
Milyarlarca hatta yüz milyonlarca satır içeren tablolarımız olduğunda, yoğun olmayan saatlerde yeniden indeksleme işlemini tamamlamak mümkün olmayabilir.
Bu durumdan kaçınmak için, geçmiş verileri bir OLTP veritabanından çıkarmak çözüm olabilir. Ancak, belirli bir eşikten daha eski olan satırları silersek, dizinleri daha da parçalı hale getiririz ve onları daha sık yeniden dizinlememiz gerekir.
Kurtarmaya SQL Bölümleme?
Üretim veritabanında yalnızca “aktif” işlemleri tutarak, geçmiş verileri kaldırmanın neden olduğu parçalanmayı önlemenin bir yolu vardır. Tüm büyük RDBMS'lerin uyguladığı fikir, bir tabloyu daha küçük parçalara ( bölümler olarak adlandırılır) bölmek ve bunları ekleme, kaldırma ve hatta tablolar arasında değiştirme yeteneği sağlamaktır (örn. yapı).
Bu e-tabloda bölümlenmiş olarak Reservations tablosuna bir göz atalım. Tablo, bölüm adları tarih dönemlerine ve diğer elektronik tablolara eşlenmiş olarak aya göre bölünmüştür. Bölümlenmiş bir tabloda bir sorgunun nasıl yürütüldüğünü görmek için birkaç alıştırma yapacağız.
Alıştırma 4: SQL'de Bölüm Sorgusu
Yukarıda bağlantısı verilen elektronik tablodan, aşağıdaki sorgu tarafından istenen verileri herhangi bir dizin kullanmadan çıkarmaya çalışın:
SELECT HotelID, ReservationID, ClientID, DateFrom, DateTo FROM Reservations WHERE DateFrom BETWEEN TO_DATE('2021-03-01','YYYY-MM-DD') AND TO_DATE('2021-03-03');Muhtemelen, ilk önce bölüm eşleme sayfasına bakmanız ve Mart 2021'den itibaren rezervasyonları içeren bölümü bulmanız gerektiğini anladınız. Bundan sonra, ilgili bölümü açtınız, verileri sırayla okudunuz ve karşılamayan satırları filtrelediniz. şart.
Basit olsa da, muhtemelen çok fazla okuduktan sonra bu kadar az satır tutmaktan hoşlanmadınız. Mart bölümünü okumak, tüm rezervasyon tablosunu okumaktan daha iyiydi ama yine de ideal değil. Peki ya indeksler?
Küresel Endeksler
RDBMS'ler, bölümlenmiş bir tablonun tüm bölümlerini kapsayacak şekilde genel bir dizin oluşturmamıza izin verir. Ancak genel ve normal dizinlerin altında nasıl çalıştığı arasında hiçbir fark yoktur: Genel dizinler bölüm farkında değildir. Bu nedenle, genel bir dizin kullanan CRUD sorguları, tablosu için bölüm haritasını içermez.
Sadece tüm bölümü bıraktığımızda bölüm haritasını güncellememiz gerekiyor. Ardından, dizinden kaldırılan bölüme işaret eden tüm satırları kaldırmamız gerekir. Bu, tüm küresel endeksin yeniden oluşturulması gerektiği anlamına gelir.
Eski öğeler kaldırılana kadar dizinler kullanılamayacağından bir kesinti penceresi gerekli kalır. Aktif bölümlerin sayısını sınırlayarak bölümleri düzenli olarak bırakabilirsek, yeniden indeksleme işlemi kesinti penceresine sığabilir. Bu nedenle, bölümlerin kullanılması, genel dizinlerin bakımı da dahil olmak üzere bakım görevleri için gereken süreyi kısaltarak orijinal soruna yardımcı olur.
Ama ya yine de kesintiyi karşılayamazsak?
Global Olarak Bölümlenmiş Dizinler
Bu strateji bu sorunu çözer: Dizini, tabloyu bölümlere ayırdığımız gibi bölümlere ayırırız. Bölüm elektronik tablosunun bağlandığı elektronik tablolarda, her bölüm, her ikisi de DateFrom tarafından bölümlenmiş, Reservations tablosunun kendi bölümünü ve IX_DateFrom adlı bir dizin sayfasını içerir.
Alıştırma 4'teki sorguyu yürütmek için, bir RDBMS önce bir dizin bölümleri haritasına bakar ve hangi bölümlerin aralıktaki tarihleri içerdiğini belirler. (Bizim durumumuzda, bu sadece bir dizin bölümüdür.) Bundan sonra, B-ağacı aramalarını kullanır, yaprak düzeyine geçer ve son olarak ilgili satır adresini kullanarak tabloya erişir.
Bir tablodan bölüm attığımız zaman, ilgili bölümü indeksten düşürmemiz yeterlidir. Kesinti süresi gerekli değildir.
Yerel Dizinler
Global olarak bölümlenmiş dizinlerin ana dezavantajı, hem tabloyu hem de ilgili dizin bölümünü düşürmeye özen göstermemiz gerektiğidir. Dizin bölümleri haritasının kendisini okumak ve sürdürmekle ilgili yalnızca küçük bir ek maliyet vardır.
Yerel dizinler benzer ancak biraz farklı bir yaklaşım içerir. Tek bir global dizini bölümlemek yerine, her tablo bölümünün içinde yerel bir dizin oluşturuyoruz. Bunu yaparken, yerel dizinler, dezavantajlarından kaçınırken, küresel olarak bölümlenmiş dizinlerin ana avantajını (yani, kesinti olmaması) paylaşırlar.
Mükemmel bir çözüm gibi görünüyor. Ancak kutlamadan önce, birkaç sorgunun olası yürütme planını inceleyelim.
Alıştırma 5: Yerel Olarak Bölümlenmiş Dizin
Bu sefer DateFrom üzerindeki yerel olarak bölümlenmiş dizini kullanarak sorguyu yeniden çalıştırmayı deneyin.
Muhtemelen bu yürütme planını kullandınız:
For all partitions where [StartDateFrom, StartDateTo) intersects ['2021-03-01', '2021-03-03'] Get first row from IX_DateFrom where DateFrom between '2021-03-01' and '2021-03-03' While found and DateFrom < '2021-03-04' Fetch Reservations.* where RowAddress = IX_DateFrom.RowAddress Write down HotelID, ReservationID, ClientID, DateFrom, DateTo Get next row from IX_DateFromTüm tarihlerin tek bir bölüme ait olduğu için şanslıyız, bu yüzden sadece bir yerel dizini geçmek zorunda kaldık. Dönem altı ay uzun olsaydı, altı yerel indeks okumamız gerekirdi.
Alıştırma 6: Zıtlık
Göreviniz, bu sefer Müşteri 124'ün Otel 1'i ziyaret ettiği dönemlerin bir listesini yapmak için Rezervasyon bölüm haritasını tekrar kullanmaktır:
SELECT DateFrom, DateTo FROM Reservations WHERE ClientID = 124 AND HotelID = 1; Burada yerel dizinlerin ana dezavantajını görebiliriz. Reservations tablosunun her bölümünden yerel dizin sayfası IX_HotelID_CientID'yi okumak zorunda kaldık:
For all partitions Get first row from IX_HotelID_ClientID where ClientID = 124 and HotelID = 1 While found and ClientID = 124 and HotelID = 1 Fetch Reservations.* where RowAddress = IX_HotelID_ClientID.RowAddress Write down DateFrom, DateTo Get next row from IX_HotelID_ClientIDBu yürütme, açıkça daha fazla blok okuyacak ve tablonun bölümlenmemesine göre daha fazla zaman alacaktır.
Bu nedenle, yoğun olmayan dönemde dizinlerimizin sağlığını korumanın bir yolunu bulmuş olsak da, strateji bazı sorgularımızı da yavaşlattı.
İş modelimiz az sayıda bölüm tutmamıza izin veriyorsa veya en azından en sık sorgular, RDBMS'nin yalnızca bir veya iki bölümü okumasına izin veren kriterler içeriyorsa, bu çözüm ihtiyacımız olan şey olabilir. Aksi takdirde, bölümlemeden kaçınıp veri modelini, dizinleri ve sorguları iyileştirmeye ve veritabanı sunucusunu geliştirmeye çalışmamız daha iyi olur.
SQL'de İndeksler: Daha Sonra Ne Öğrenilecek?
Bu, yolculuğumuzun sonu. SQL Dizinleri Açıklamasında, tüm modern RDBMS'lerde ortak olan dizin uygulamasına odaklandım. Ayrıca, genellikle veritabanı yöneticilerini ilgilendiren konular pahasına, uygulama geliştiricilerin ilgilendiği konulara da odaklandım. İkincisi, doldurma faktörünün dizin parçalanması üzerindeki etkisini araştırmak için iyi olur, ancak her iki roldeki insanlar hakkında daha fazla bilgi okumanın faydalı olacağı muhtemeldir:
- Veri ve dizin önbelleğe alma
- Karma, GiST, bitmap ve sütun deposu dizinleri gibi B ağacı olmayan dizin yapıları
- Kümelenmiş dizinler (Oracle'da dizinle düzenlenmiş tablolar olarak bilinir)
- fonksiyonel indeksler
- Kısmi dizinler
Tartıştığımız bölümleme yaklaşımı, aralık bölümlemedir . En yaygın olarak kullanılan bölümleme türüdür, ancak karma bölümleme ve liste bölümleme gibi başkaları da vardır. Ayrıca, bazı RDBMS'ler birden çok bölümleme düzeyi seçeneği sunar.
Son olarak, SQL geliştiricileri, RDBMS sorgu yürütmesiyle ilgili diğer önemli konuları (önce, sorgu ayrıştırma, ardından maliyet tabanlı yürütme planı derlemesi, önbelleğe alma ve yeniden kullanma) araştırmak için iyi yapacaktır.
Deneyim sahibi olduğum dört RDMBS için sonraki adımlar olarak bu kaynakları öneriyorum:
kehanet
- Optimize Edici'ye Genel Bakış
- İndeksler ve İndeks-Düzenli Tablolar
- Dizinleri Yönetme
- Bölümlere Genel Bakış
- Bölümleme Kılavuzu
- Tom'a sor
PostgreSQL
- Sorgu İşleme
- PostgreSQL'deki dizinler
- PostgreSQL'deki İndeksler (Resmi Belgeler)
- Tampon Yönetimi
- Tablo Bölümleme
- Bölümleme Kılavuzu
Microsoft SQL Sunucusu
- Sorgu İşleme Mimarisi
- dizinler
- Bölümlenmiş Tablolar ve Dizinler
MySQL/MariaDB
- Sorgu Yürütme Planını Anlama
- Optimizasyon ve Dizinler
- Bölümleme - Temel Bilgiler
- Bölümleme - Belgeler
- MariaDB Belgeleri: Sorgu Optimizasyonu ve Dizinler
