MySQL ile Hiyerarşik Veriler ikinci bölüm: iç içe yerleşim kalıbı
Serinin bir önceki yazısında tümleşik yapı kalıbını anlatmıştık, kaldığımız yerden yani tümleşik yapı kalıbının ( Adjancy List Model ) limitlerini aşan, İç İçe Yerleşim Kalıbına (nested set model) geçiyoruz.
Makalenin diğer adı, iç içe yerleşim kalıbı (Nested Set Model)
Bu modelde,hiyerarşiye yeni bir gözle bakacağız, buradaki gibi hiyerarşi ağacı değil de, iç içe geçmiş kümeler gibi. Yani hiyerarşimiz şu şekilde;

bu yazıda iç içe yerleşim diagramı olarak bahsi geçen birbirlerini kapsayan kümelerle ifade edilmiş hiyerarşi diagramı
Bir tabloda, bu kümelerin yerleşim yerlerini sağ ve sol değerleri temsil edecek şekilde bu hiyerarşiyi kuracağız:
CREATE TABLE nested_category (
category_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
);
INSERT INTO nested_category
VALUES(1,'ELECTRONICS',1,20),(2,'TELEVISIONS',2,9),(3,'TUBE',3,4),
(4,'LCD',5,6),(5,'PLASMA',7,8),(6,'PORTABLE ELECTRONICS',10,19),
(7,'MP3 PLAYERS',11,14),(8,'FLASH',12,13),
(9,'CD PLAYERS',15,16),(10,'2 WAY RADIOS',17,18);
SELECT * FROM nested_category ORDER BY category_id;
+-------------+----------------------+-----+-----+
| category_id | name | lft | rgt |
+-------------+----------------------+-----+-----+
| 1 | ELECTRONICS | 1 | 20 |
| 2 | TELEVISIONS | 2 | 9 |
| 3 | TUBE | 3 | 4 |
| 4 | LCD | 5 | 6 |
| 5 | PLASMA | 7 | 8 |
| 6 | PORTABLE ELECTRONICS | 10 | 19 |
| 7 | MP3 PLAYERS | 11 | 14 |
| 8 | FLASH | 12 | 13 |
| 9 | CD PLAYERS | 15 | 16 |
| 10 | 2 WAY RADIOS | 17 | 18 |
+-------------+----------------------+-----+-----+
Burada , ltf left, yani sol rgt ise right yani sağ demek. Fakat right ve left MySQL’de ayrılmış sözcükler olduğu için bu kısaltmaları kullandık. Tercihe göre sag veya sol, sarimsak veya sogan da diyebilirsiniz :-)
Şimdi asıl soru, sağ ve sol değerlerini neye göre atıyoruz? Küme örneğinde, sınırları numaralandırdığımızı düşnün;

Veya numaralandırmayı klasik hiyerarşi tablosundan da yapabiliriz;
Ağaç hiyerarşisinde, sağdan sola, her katmanın bitişinde onun bi üstüne uğrayacak ve bu şekilde devam ederek tepe noktasında bitecek bir yoldan gitmemiz gerekecektir. Böylece numaralandırılmış sayıların arası kümeler olacak, ve başka sayılar arasında, başka kapsama alanları oluşacağından sonsuz bir hiyerarşi tanımına erişebiliriz; tam bizim istediğimiz şey. Dikiş diker gibi ulaştığımız bu sonuca (ilk şekil), iç içe geçmiş sıralı ağaç-hiyerarşisi ( çeviri tartışılır; preorder tree traversal algorithm ) algoritması denmekte.
Bütün hiyeraşiyi getirmek
Nesnelerin (node) lft değeri her zaman ebeveyn nesnenin ( parent node ) lft (sol) ve rgt (sağ) değerleri arasında görüneceğinden, self-join kullanarak ve böylelikle düğümle ebeveyni (parent) bağlantılandırarak bütün hiyerarşi ağacını elde edebiliriz.
SELECT node.name
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND parent.name = 'ELECTRONICS'
ORDER BY node.lft;
+----------------------+
| name |
+----------------------+
| ELECTRONICS |
| TELEVISIONS |
| TUBE |
| LCD |
| PLASMA |
| PORTABLE ELECTRONICS |
| MP3 PLAYERS |
| FLASH |
| CD PLAYERS |
| 2 WAY RADIOS |
+----------------------+
Daha tümleşik yerleşim kalıbındaki önceki örneklerimizden farklı olarak, bu sorgu hiyerarşinin derinliği önemli olmaksızın tamamını getirecektir. Rgt’nin değerinin BETWEEN içinde olması bizim için sorun teşkil etmiyor, nitekim rgt değeri her zaman aynı ebebeyn objenin (parent node) lft değerinin aralığını kapsayacaktır.
Bütün çocuk objeleri ( leaf node ) getirmek
İçiçe yerleşim kalıbında, bunu yapmak tümleşik kalıpda LEFT JOIN’den bile daha kolaydır. Eğer nester_category tablomuza bakarsanız, objelerin lft ve rgt değerlerinin ardışık sıralandığını farkedebilirsiniz. Tüm yapmanız gereken rgt değerinin, lft’den büyük olduğu satırları almaktır, yani rgt=lft+1.
SELECT name
FROM nested_category
WHERE rgt = lft + 1;
+--------------+
| name |
+--------------+
| TUBE |
| LCD |
| PLASMA |
| FLASH |
| CD PLAYERS |
| 2 WAY RADIOS |
+--------------+
Tek bir hiyerarşi yolunu almak
İçiçe yerleşim kalıbıyla, çok self-join kullanma zahmetine girmeden hiyerarşi yolunu elde edebiliriz.
SELECT parent.name
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.name = 'FLASH'
ORDER BY parent.lft;
+----------------------+
| name |
+----------------------+
| ELECTRONICS |
| PORTABLE ELECTRONICS |
| MP3 PLAYERS |
| FLASH |
+----------------------+
Hiyearşi objelerinin derinliğini getirmek
Hiyerarşinin tümünü elde etmiştik, fakat ya her bir objenin ne kadar derinlikte olduğu bilgisini istiyorsak? Bunu kolayca gene saf sql ile MySQL’in COUNT() fonksiyonu ve GROUP BY bölümüyle başarabiliriz. Bu yöntemi hangi hiyerarşi yolunu istersek isteyelim uygulayabiliriz, fakat madem tüm hiyerarşiden yola çıktık, bütün hiyerarşi ağacı için yapacağımız geliştirme şöyle olacaktır:
SELECT node.name, (COUNT(parent.name) - 1) AS depth
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
ORDER BY node.lft;
+----------------------+-------+
| name | depth |
+----------------------+-------+
| ELECTRONICS | 0 |
| TELEVISIONS | 1 |
| TUBE | 2 |
| LCD | 2 |
| PLASMA | 2 |
| PORTABLE ELECTRONICS | 1 |
| MP3 PLAYERS | 2 |
| FLASH | 3 |
| CD PLAYERS | 2 |
| 2 WAY RADIOS | 2 |
+----------------------+-------+
Aynı zamanda, buradaki derinliği görsel olarak da belirtmek istiyorsak CONCAT ve REPEAT fonksiyonları yardımımıza gelecektir:
SELECT CONCAT( REPEAT(' ', COUNT(parent.name) - 1), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
ORDER BY node.lft;
+-----------------------+
| name |
+-----------------------+
| ELECTRONICS |
| TELEVISIONS |
| TUBE |
| LCD |
| PLASMA |
| PORTABLE ELECTRONICS |
| MP3 PLAYERS |
| FLASH |
| CD PLAYERS |
| 2 WAY RADIOS |
+-----------------------+
Tabii ki, web uygulamalarında yukarıdaki gibi bir ASCII Art’ın pek yeri yok. Hiyerarşiyi görsel olarak sunacaksak bizim işimiz daha çok <li> ve <ul> ‘lerle, bu durumda ikinci SQL’i yok sayalım. Sadece derinlik bilgisi rekürsif/özyinelemeli/kendini çağıran (recursive) fonksiyona ihtiyaç duymadan tek bir döngüde oluşturmamıza olanak verecektir.
Alt hiyerarşi ağacında (sub-tree) derinlik
Bir sub-tree’de derinlik bilgisine ihtiyacımız olduğunda, bi önceki örnekteki gibi self-joinimizde çocuk veya ebeyn tablolarında limit koyamayız; aldığımız sonuçlar bozulacaktır. Bunun yerine, yeni bir alt-sorgu (subquery) olarak üçüncü bir self-join ekliyoruz, böylece derinliği almak için yeni başlangıç noktasını bu sorguda belirtebiliriz.
SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth
FROM nested_category AS node,
nested_category AS parent,
nested_category AS sub_parent,
(
SELECT node.name, (COUNT(parent.name) - 1) AS depth
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.name = 'PORTABLE ELECTRONICS'
GROUP BY node.name
ORDER BY node.lft
)AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.name = sub_tree.name
GROUP BY node.name
ORDER BY node.lft;
+----------------------+-------+
| name | depth |
+----------------------+-------+
| PORTABLE ELECTRONICS | 0 |
| MP3 PLAYERS | 1 |
| FLASH | 2 |
| CD PLAYERS | 1 |
| 2 WAY RADIOS | 1 |
+----------------------+-------+
Bu işlevi kök node’lar dahil, herhangi bir node ismiyle gerçekleştirebiliriz. Derinliğin başlangıcı tam da istediğimiz gibi, her zaman söz konusu ismini veya id’sini verdiğimiz node kabul edilir.
Hiyearşide sınırlı derinliklerin getirilmesi
Bu başlığın birebir çevirisi “Bir objenin en yakın ikincil dereceden derinliğinin getirilmesi” idi, fakat daha konudan yazarken yabancılaşınca, korkunca, farklı şekilde bir başlık koymayı uygun gördüm. Diyelim ki, hiyerarşinin tamamının değil, sadece bir alt basamağına kadar getirmek istiyoruz, geri kalanını almak istemiyoruz. Aslında çok basit ve zaman zaman istediğimiz birşey bu, tümleşik yapı kalıbında, rekürsif fonksiyonumuzu kaç kere çağıracağımıza göre bunu ayarlıyorduk. Fakat şimdi yeni kalıbımızda gene saf SQL’de bir önceki örneğimize HAVING ekleyerek bunu çok kolay yapabiliriz:
SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth
FROM nested_category AS node,
nested_category AS parent,
nested_category AS sub_parent,
(
SELECT node.name, (COUNT(parent.name) - 1) AS depth
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.name = 'PORTABLE ELECTRONICS'
GROUP BY node.name
ORDER BY node.lft
)AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.name = sub_tree.name
GROUP BY node.name
HAVING depth < = 1
ORDER BY node.lft;
+----------------------+-------+
| name | depth |
+----------------------+-------+
| PORTABLE ELECTRONICS | 0 |
| MP3 PLAYERS | 1 |
| CD PLAYERS | 1 |
| 2 WAY RADIOS | 1 |
+----------------------+-------+
Eğer ebebeyn objeyi istemiyorsak, basitçe depth<=1 yerine depth=1 işimizi görecektir.
İçiçe yerleşimde sayım işlevleri
Öncelikle sayım yapacaksak, örneklerimizi kolaylaştırması açısından bir de ürün tablosu ekleyelim.
CREATE TABLE product(
product_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(40),
category_id INT NOT NULL
);
INSERT INTO product(name, category_id) VALUES('20" TV',3),('36" TV',3),
('Super-LCD 42"',4),('Ultra-Plasma 62"',5),('Value Plasma 38"',5),
('Power-MP3 5gb',7),('Super-Player 1gb',8),('Porta CD',9),('CD To go!',9),
('Family Talk 360',10);
SELECT * FROM product;
+------------+-------------------+-------------+
| product_id | name | category_id |
+------------+-------------------+-------------+
| 1 | 20" TV | 3 |
| 2 | 36" TV | 3 |
| 3 | Super-LCD 42" | 4 |
| 4 | Ultra-Plasma 62" | 5 |
| 5 | Value Plasma 38" | 5 |
| 6 | Power-MP3 128mb | 7 |
| 7 | Super-Shuffle 1gb | 8 |
| 8 | Porta CD | 9 |
| 9 | CD To go! | 9 |
| 10 | Family Talk 360 | 10 |
+------------+-------------------+-------------+
Şimdi her kategorinin kaç ürüne sahip olduğu bilgisini bir sorguyla alalım:
SELECT parent.name, COUNT(product.name)
FROM nested_category AS node ,
nested_category AS parent,
product
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.category_id = product.category_id
GROUP BY parent.name
ORDER BY node.lft;
+----------------------+---------------------+
| name | COUNT(product.name) |
+----------------------+---------------------+
| ELECTRONICS | 10 |
| TELEVISIONS | 5 |
| TUBE | 2 |
| LCD | 1 |
| PLASMA | 2 |
| PORTABLE ELECTRONICS | 5 |
| MP3 PLAYERS | 2 |
| FLASH | 1 |
| CD PLAYERS | 2 |
| 2 WAY RADIOS | 1 |
+----------------------+---------------------+
Bu bizim tipik tüm hiyerarşiyi alma sorgumuzda WHERE bölümünde product ile kategori arasında ilişkiyi sağladık ve sayım için COUNT(), ve onun filtresi için GROUP BY ekledik. Gördüğünüz gibi aynı zamanda ürün sayıları doğrudan alt node’a bağlanmış olsa da onun ebebeyn nodelarına da çoğu zaman isteneceği gibi yansımış durumda.
Yeni obje eklemek
Ağacımızı nasıl sorgulayacağımızı öğrendiğimize göre artık nasıl onu değiştirebileceğimize geçebiliriz. Tekrar içiçe yerleşimin diagramına bakalım:
Yeni objemizi TELEVISIONS ve PORTABLE ELECTRONICS objeleri arasına yerleştireceksek, yeni objenin lft ve rgt değerlerinin 10 ve 11 olması gerekir, buradan yeni objenin sağında kalan bütün objelerin lft ve rgt değerlerinin iki artacağını söyleyebiliriz. Bütün bu işi, stored procedure ile yapabileceğimiz gibi, kullanmadan da işlem güvenliğini LOCK TABLES ile sağlayarak yapabiliriz.
LOCK TABLE nested_category WRITE;
SELECT @myRight := rgt FROM nested_category
WHERE name = 'TELEVISIONS';
UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myRight;
UPDATE nested_category SET lft = lft + 2 WHERE lft > @myRight;
INSERT INTO nested_category(name, lft, rgt) VALUES('GAME CONSOLES', @myRight + 1, @myRight + 2);
UNLOCK TABLES;
SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
ORDER BY node.lft;
+-----------------------+
| name |
+-----------------------+
| ELECTRONICS |
| TELEVISIONS |
| TUBE |
| LCD |
| PLASMA |
| GAME CONSOLES |
| PORTABLE ELECTRONICS |
| MP3 PLAYERS |
| FLASH |
| CD PLAYERS |
| 2 WAY RADIOS |
+-----------------------+
Eğer bir çocuk objeyi, bir objenin yanına değil, hiyerarşide onun altına yerleştirmek istiyorsak bu sefer bir önceki sorgumuzda küçük bir değişiklik yapmamız gerekecek:
LOCK TABLE nested_category WRITE;
SELECT @myLeft := lft FROM nested_category
WHERE name = '2 WAY RADIOS';
UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myLeft;
UPDATE nested_category SET lft = lft + 2 WHERE lft > @myLeft;
INSERT INTO nested_category(name, lft, rgt) VALUES('FRS', @myLeft + 1, @myLeft + 2);
UNLOCK TABLES;
Bu örnekte, sag ve sol değerlerinin uygun değerleri almasıyla, geri kalan değerleri de buna göre genişlettik, tekrar kontrol edersek sorun olmadığını görürüz:
SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
ORDER BY node.lft;
+-----------------------+
| name |
+-----------------------+
| ELECTRONICS |
| TELEVISIONS |
| TUBE |
| LCD |
| PLASMA |
| GAME CONSOLES |
| PORTABLE ELECTRONICS |
| MP3 PLAYERS |
| FLASH |
| CD PLAYERS |
| 2 WAY RADIOS |
| FRS |
+-----------------------+
Gökçe’den not:
Bu yapı anlatılırken, kolay anlaşılması bakımından oldukça ’sıkı’ bir yapı kullanılmış. Yapıyı inceleyen birisi, lft ve rgt değerlerinin bu kadar sıkı yani 1 numarayla dip dibe ardışık gitmese de çalışacağını hemen anlayacaktır. Bu sıklığa verilmesi gereken ‘padding’ olarak bakıyoruz, bu kalıpta padding arasındaki boşluk daha fazla tutulabilir ve bu bir sorun teşkil etmez (margin). Margin verilmesi durumunda, araya girecek yeni node’ların rgt ve lft değerlerinin tamamının değişmesi de gerekmeyecektir. Böylece daha sonra bol satır değişliği gerektiren alignment işlemi performansın daha verimli kullanılabileceği bir zamanda yapılabilir.
Objeleri silmek
Hiyerarşi ağacını değiştirmekle ilgili en çok ihtiyaç duyulan bir başka iş, objelerin silinmesi. Bu işle ilgilenirken, önemli olan silinecek objenin bulunduğu pozisyon. Taban objelerin, diğerlerine göre silinmesi daha kolay, çünkü ortada kalan ebeveynsiz öksüz çocuklarla baş etmemiz gerekmiyor.
Eğer taban obje sileceksek, bu işlem tıpkı yeni bir obje koymanın tersi sağayabliriz, tek yapacağımız ‘padding’ i daraltarak objelerin sağına (rgt) tekrar ayar vermek.
LOCK TABLE nested_category WRITE;
SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1
FROM nested_category
WHERE name = 'GAME CONSOLES';
DELETE FROM nested_category WHERE lft BETWEEN @myLeft AND @myRight;
UPDATE nested_category SET rgt = rgt - @myWidth WHERE rgt > @myRight;
UPDATE nested_category SET lft = lft - @myWidth WHERE lft > @myRight;
UNLOCK TABLES;
Tekrar kontrol etmek namına, hiyerarşide herşey yolundamı bakalım:
SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
ORDER BY node.lft;
+-----------------------+
| name |
+-----------------------+
| ELECTRONICS |
| TELEVISIONS |
| TUBE |
| LCD |
| PLASMA |
| PORTABLE ELECTRONICS |
| MP3 PLAYERS |
| FLASH |
| CD PLAYERS |
| 2 WAY RADIOS |
| FRS |
+-----------------------+
Bu yaklaşımı aynı şekilde o ve bütün çocuklarını da silmekte kullanabiliriz. Tek bir yolu getirdiğimiz sorguya benzer:
LOCK TABLE nested_category WRITE;
SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1
FROM nested_category
WHERE name = 'MP3 PLAYERS';
DELETE FROM nested_category WHERE lft BETWEEN @myLeft AND @myRight;
UPDATE nested_category SET rgt = rgt - @myWidth WHERE rgt > @myRight;
UPDATE nested_category SET lft = lft - @myWidth WHERE lft > @myRight;
UNLOCK TABLES;
Son bir kere başarıyla tüm alt ağacı silerek bitirdik:
SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
ORDER BY node.lft;
+-----------------------+
| name |
+-----------------------+
| ELECTRONICS |
| TELEVISIONS |
| TUBE |
| LCD |
| PLASMA |
| PORTABLE ELECTRONICS |
| CD PLAYERS |
| 2 WAY RADIOS |
| FRS |
+-----------------------+
Gereksinim duyabileceğimiz bir diğer durum da, ebebeyni silmek, fakat çocuklarına dokunmamak. Bu gibi bir duruma örneğin personel müdürünün işten kovulmasında rastlayabiliriz. Bu durumda iki şeye rastlarız, isminin değişmesi ve hiyerarşinin ve yönetimin sağlanabilmesi için bütün alt personelin bir sonraki ebebeyne bağlanması. İkinci seçenek, eğer hemen yerine konulamıyorsa gerçek yaşamda karşılaşılan ve ihtiyaç oluşturan durumdur. Yani silinme sonucu öksüz kalan çocukları, bir basamak yukarıdaki ebebeyne taşıyacağız:
LOCK TABLE nested_category WRITE;
SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1
FROM nested_category
WHERE name = 'PORTABLE ELECTRONICS';
DELETE FROM nested_category WHERE lft = @myLeft;
UPDATE nested_category SET rgt = rgt - 1, lft = lft - 1 WHERE lft BETWEEN @myLeft AND @myRight;
UPDATE nested_category SET rgt = rgt - 2 WHERE rgt > @myRight;
UPDATE nested_category SET lft = lft - 2 WHERE lft > @myRight;
UNLOCK TABLES;
Bu durumda, ( ebebeyn objenin lft değerinin kalkmasından dolayı oluşacağı boşluğu gidermek için ) objenin çocuklarından bir çıkarırken, objenin sağındaki bütün objelerden ( çocuksuz objelerde genişlik iki olacağından ) iki çıkarıyoruz . Ve tekrar, son kez herşey yolunda gitmiş mi bakıyoruz:
SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
ORDER BY node.lft;
+---------------+
| name |
+---------------+
| ELECTRONICS |
| TELEVISIONS |
| TUBE |
| LCD |
| PLASMA |
| CD PLAYERS |
| 2 WAY RADIOS |
| FRS |
+---------------+
Diğer durumlar, artık iş akışının içine gireceğinden ve çok çeşitli olabileceğinden bu yazının içine dahil edilmedi. Fakat kendi tecrübelerinizi burada paylaşamayacağınız anlamına gelmiyor.
Gökçe’den notlar
Umarım, hem bu, hem bir önceki Tümleşik Yapı Modeli işinize yaramıştır. Bu yöntem ve algoritma arasında bir karşılaştırma yapılabilir, fakat birbirne karşıt değillerdir. Nitekim, tümleşik yapı kalıbına en fazla kendini yineleyen bir veri saklama yöntemi denebilecekken, bu yazıda anlatılan iç içe yerleşim bir algoritmadır. Bir diğer not olarak, pek çok kişi neresini savunacağını bilmediğinden ama “iyi” göründüğünden ötürü ilk akla gelen “nested set daha performanslı” argümanını savunsa da, konunun performansla değil, daha çok işlevsellikle ilgili olduğu anlaşılabilir. Çok derin bir örnek teşkil etmese de, mesela TABLE LOCK kullanan DB Enginelerinde (örneğin MyISAM) yeni bir kategori eklemek, hiyerarşideki yerini değiştirmek, veya çıkarmak için tablonun yarısına UPDATE çekmesi performansdan götürürken (ki bu kaybın bir kısmı margin ile halledilebilir, başka konu), tek bir sorguda bütün hiyerarşinin alınabilmesi hem performans, hem işlevsellikte artı hanesine yazılır.
Google‘layarak pek çok farklı kaynağa, wikipedia’da konudan konuya atlayarak konu üzerinde bilginizi çoğaltabilirsiniz. Siz zaten bulursunuz fakat ben burada çok ufak ama değerli bir yazışmayı paylaşmak istiyorum: Stored Procedures vs Nested Set

Ekim 4th, 2008 @ 2:17 am
Çok güzel bir makale. Benim de, ilk gördüğüm anda delicious üzerine kaydettiğim nefis bir makale. Üstelik bu makaleden (orjinalinden) sonra, 1-2 sitemde de kategori yapısını ve SQL sorgularını bu makaledeki gibi değiştirince inanılmaz faydasını gördüm. Böyle makaleleri çok daha sık görmek, biz programcıların işini inanılmaz kolaylaştıracaktır.
Buradan makalenin yazarına (Mike Hillyer) da tekrar teşekkür etmek istiyorum. Size de bu makaleyi Türkçe programlama literatürüne kazandırdığınız için gerçekten çok teşekkürler.
Ekim 4th, 2008 @ 5:13 am
Teşekkürler, buarada yazının devamı olduğu için orjinaline atıfta bulunmayı unutmuşum, MyASQL AB deyip geçmişim, böylece yorumunuzla bu eksiklik de giderilmiş oldu.
Ayrıca öyle gezerken, bilindik tümleşik yapıda hiyerarşi haritasını hardcode ile uğraşmadan almak isteyenler için rastladığım bir stored procedure: http://db4free.blogspot.com/2005/09/menu-management-with-stored-procedures.html