Katılmak tembel insanlar için mi?


169

Geçenlerde bana JOINs (SQL) işe yaramaz olduğunu iddia başka bir geliştirici ile bir tartışma vardı. Bu teknik olarak doğrudur, ancak birleşimleri kullanmanın kodda (C # veya Java) birkaç istek ve bağlantı tablosu yapmaktan daha az verimli olduğunu ekledi.

Onun için katılımlar performansı umursamayan tembel insanlar içindir. Bu doğru mu? Birleştirmeler kullanmaktan kaçınmalı mıyız?


114
Hayır. Veritabanları birleştirme yapmak üzere optimize edilmiştir, özellikle büyük veri kümeleri için son derece hızlıdır. Uygulamanızın on binlerce satırı yüklemesini ve bunları manuel olarak birleştirmesini istemezsiniz.
halfdan

91
Programlama dilleri tembel insanlar içindir; CPU talimatlarını elle kodlamaktan daha az verimlidir. :)
Michael McGowan

76
Geliştiricinin adı nedir? Onu asla işe almadığımdan emin olmak istiyorum.
Joe

39
@Michael meh, gerçek programcılar kelebekler kullanıyor ...
Marc Gravell

14
Yeniden "bu doğru" - hayır, öyle değil. Veritabanları küme teorisi ile çalışır; setler katıldı çok güzel ve kullanışlı bir şekilde çalışır ...
Marc Gravell

Yanıtlar:


188

Hayır, inanılmaz derecede yanlış görüşlere sahip geliştiricilerden kaçınmalıyız.

Çoğu durumda, veritabanı birleştirmesi, istemci üzerinden yapılan her şeyden birkaç kat daha hızlıdır, çünkü DB gidiş dönüşlerini önler ve DB birleştirmeyi gerçekleştirmek için dizinleri kullanabilir.

Başımın en üstünde, doğru bir şekilde kullanılan birleştirmenin eşdeğer istemci tarafı işleminden daha yavaş olacağı tek bir senaryo bile hayal bile edemiyorum.

Düzenleme: Özel istemci kodunun basit bir DB birleşiminden daha verimli bir şeyler yapabileceği bazı nadir durumlar vardır (meriton tarafından açıklamaya bakın). Ancak bu çok istisnadır.


1
3 yollu birleşimlere ne dersiniz? Onları "kodda" yapmaktan daha iyi olacağınız durumlar yok mu?
julien_c

56
Uygulamanın sunucusunda katılan yapabilirsiniz veritabanı üzerinde katılmadan ağ üzerinden gönderilen sonuç kümesindeki şiddetli fazlalık neden olursa daha verimli. A'daki her satırın B'deki 20 satırla ilişkili olduğu A ve B tablolarını düşünün, B'de sadece 100 satır var ve A'dan ilk 1000 satırı B'den ilişkili satırlarla getirmek istiyoruz. Veritabanına katılmak 20 ile sonuçlanacak * Ağ üzerinden 1000 tuple gönderildi. Birleştirme uygulama sunucusunda yapılırsa (önce tüm B tablosunu belleğe getirir), ağ üzerinden yalnızca 100 + 1000 satır gönderilir.
meriton

7
Ancak, veri tabanındaki birleştirmelerin çoğu durumda çok daha hızlı olduğu ve bu nedenle sadece kolaylık değil, aynı zamanda bir zorunluluk olduğu konusunda kesinlikle haklısınız.
meriton

13
Microsoft'ta SQL Server üzerinde çalışan bazı geliştiricilerle konuşmak için yeterince şanslıyım. Sorgularda yaptıkları optimizasyonları baş döndürücü hale getirecektir. Bundan daha akıllı olduklarını düşünen herkesin şapırtılı olması gerekir.
riwalk

2
meriton Biraz şaşırdım; İstemci kütüphanesinin çapraz birleştirmeleri optimize etmesini beklerdim.
Phil Lello

83

Bana meslektaşınız bir no-sql belge veritabanı veya anahtar / değer deposu ile iyi yapacağım gibi geliyor. Hangi kendileri çok iyi araçlar ve birçok sorun için iyi bir uyum.

Ancak, ilişkisel veritabanı kümelerle çalışmak için büyük ölçüde optimize edilmiştir. Çok sayıda gidiş-dönüş yolculuğundan çok daha verimli olan birleşimlere dayalı olarak verileri sorgulamanın birçok, birçok yolu vardır . Bu, bir rdbms'nin çok yönlülüğünün geldiği yerdir. Aynı şeyi bir nosql mağazasında da yapabilirsiniz, ancak genellikle sorgunun her farklı doğası için uygun ayrı bir yapı oluşturursunuz.

Kısacası: Katılıyorum. RDBMS'de birleşimler esastır . Bunları kullanmıyorsanız, RDBMS olarak kullanmıyorsunuzdur.


46

Genel durumda yanılıyor.

Veritabanları, optimize edici ipuçları, tablo dizinleri, yabancı anahtar ilişkileri ve muhtemelen diğer veritabanı satıcısına özgü bilgilerin yardımıyla çeşitli yöntemler kullanarak optimizasyon yapabilir.


1
Veritabanlarıyla çalışmaya başladığımda, birleştirme performansını yenebileceğime dair aynı inanca sahip olduğumu itiraf etmeliyim. Ancak DB tarafından ne kadar hızlı birleşimlerin yapıldığını anlamak uzun sürmedi. Aslında bu durumda onu aptal olarak reddetmektense çalışanla açık bir şekilde tartışmak daha iyi diyebilirim.
LegendLength

1
@LegendLength Çok akıllı olmasalar bile bunun doğru olduğunu söyleyebilirim. Zekayı varsaymaya gerek yok, çünkü yaptığımız hataları hatırlıyoruz (aslında benim için o kadar akıllı olmadıkları anlamına gelebilir ...) Daha basit: Nadiren işten çıkarmaya yardımcı olur. Arada sırada yanlış olmak sorun değil!
16'da

24

Hayır, yapmamalısın.

Veritabanları özellikle veri kümelerini (açıkça ....) işlemek için tasarlanmıştır. Bu nedenle bunu yaparken inanılmaz derecede verimlidirler. Esasen kendi kodunda manuel birleştirme olanı yaparak, iş için özel olarak tasarlanmış bir şeyin rolünü üstlenmeye çalışıyor. Kodunun veritabanındaki kadar verimli olma şansı çok uzak.

Bir yana, birleştirme olmadan, bir veritabanı kullanmanın amacı nedir? metin dosyalarını da kullanabilir.


2
Katılmadan bile? Otomatik bellek içi eşleme, otomatik sorgu önbellekleme, çoğu dosya sisteminde hiç gerçekleşmeyen diğer birçok otomajik şey. Ah, ince kontrol edilebilir işlemlerden bahsettim mi?
Piskvor binadan ayrıldı

19

"Tembel" daha az kod yazmak isteyen insanlar olarak tanımlanırsa, o zaman katılıyorum. Eğer "tembel" yapmakta iyi olduklarını yapmak isteyen araçlar olarak tanımlanırsa, katılıyorum. Bu yüzden, sadece Larry Wall (iyi programcıların nitelikleri ile ilgili) konusunda hemfikirse, ben de ona katılıyorum.


Tembelliğin hassasiyetini ekledim: performansları umursamayan ve daha az kod yazmayı tercih eden tembel insanlar için. Bence katılımlar tembel insanlar için ama bu durumda katılımlar da birkaç istek daha iyidir.
Bastien Vandamme

3
@ Dan Dane: Katılımlar tembel insanlar içindir, evet. Muhtemelen iyi performans gösterecekleri diktir.
Piskvor binadan ayrıldı

16

Ummm, birleşmeler ilişkisel veritabanlarının tabloları birbiriyle ilişkilendirmesidir. Ne elde ettiğinden emin değilim.

Veritabanına birkaç çağrı yapmak bir çağrıdan daha verimli olabilir mi? Artı sql motorları bu tür bir şey yapmak için optimize edilmiştir.

Belki iş arkadaşınız SQL öğrenmek için çok tembeldir.


12

Evet yapmalısın.

Ve performans nedeniyle C # yerine C ++ kullanmalısınız. C # tembel insanlar içindir.

Hayır hayır hayır. Performans nedeniyle C ++ yerine C kullanmalısınız. C ++ tembel insanlar içindir.

Hayır hayır hayır. Performans nedeniyle C yerine derleme kullanmalısınız. C tembel insanlar içindir.

Evet, şaka yapıyorum. birleştirmeden daha hızlı programlar yapabilir ve birleştirmeden daha az bellek kullanarak programlar yapabilirsiniz. AMA birçok durumda, geliştirme süreniz CPU zamanı ve belleğinden daha önemlidir. Biraz performanstan vazgeçin ve hayatınızın tadını çıkarın. Küçük performans için zaman kaybetmeyin. Ve ona "Neden yerinizden ofisinize düz bir otoyol yapmıyorsunuz?"


1
Şimdiye kadar tüm cevaplarınıza baktım ve çok komikler. Lütfen gelmeye devam et. Ya şu ya da blogunuza nereden abone olabilirim?
Gerry

11

"Bu teknik olarak doğrudur" - benzer şekilde, bir SQL veritabanı işe yaramaz: bir grup CSV dosyası kullanarak ve kodda ilişkilendirerek aynı sonucu elde edebileceğinizde bir tane kullanmanın anlamı nedir? Heck, herhangi bir soyutlama tembel insanlar için, doğrudan donanımda makine kodunda programlamaya geri dönelim! ;)

Ayrıca, en kıvrımlı durumlar hariç, tüm beyanı doğru değildir: RDBMS'ler JOIN'ları yapmak için büyük ölçüde optimize edilmiştir hızlı . İlişkisel veritabanı yönetim sistemleri, değil mi?


2
+1 Eğer OP önceki cümle unnecessaryyerine daha çok söz söyleseydi "... teknik olarak doğru" ifadesi daha iyi çalışırdı useless. Birleşmelerin işe yaramaz olduğunu söylemek, dikkate alınması gereken hiçbir teknik olmadan kesinlikle yanlıştır. Her durumda, OP'ler ve meslektaşınızın RDBMS'lerin noktasını yanlış anlaması çok nadir değildir: stackoverflow.com/q/5575682/47550
Paul

7

Çalıştığım son şirket de SQL birleşimlerini kullanmadı. Bunun yerine bu işi yatay olarak ölçeklendirmek için tasarlanmış uygulama katmanına taşıdılar. Bu tasarımın mantığı veritabanı katmanında çalışmaktan kaçınmaktır. Genellikle darboğaz haline gelen veritabanıdır. Uygulama katmanını veritabanından çoğaltmak daha kolaydır. Başka sebepler olabilir. Ama şimdi hatırlayabildiğim bu.

Evet, uygulama katmanında yapılan birleştirmelerin, veritabanı tarafından yapılan birleştirmelere göre yetersiz olduğunu kabul ediyorum. Daha fazla ağ iletişimi de.

Lütfen SQL birleşmelerinden kaçınmaya sert bir şekilde dayanmadığımı unutmayın.


Bu, sizin durumunuzdaki JOIN'lara karşı rasyonel bir argüman gibi geliyor. FB Mühendislik'in bloglarına benzer bir şey gönderdiğini hatırlıyorum - ölçeklendirme de en önemli önceliğiydi. Ne yazık ki, programcılar sadece küçük% Böyle bir işlem yapmanız gerekecektir, ancak birçok düşünüyorum "OMG Facebook da bunu yapmaz çünkü" yaptıkları;)
Piskvor bina bıraktı

tamam, veritabanı sunucusunu aşırı yüklemek için yeterli trafiğe sahip olduğunuz bir kurumsal çözümde bu dikkate değer olabilir, ancak raporlanan saklı yordamın veya zamanlanmış yedeklemenin performansı çivileme olasılığı daha yüksektir. Veritabanları, özellikle yardımcı olacak dizinler varsa, birleşimlerde iyidir
Jodrell

@Jodrell: Evet katılımda iyidirler; yine, daha fazla güç elde etmek için birleşimlerin zarafetini düşürmeniz gereken köşe kutuları var. Tanıştığım bir tür durum; mümkün olan her çözümü denedik ve gerçekten de bu çok özel bir durumda birleştirme gerektirmeyen çözüm en hızlıydı . Ve hayır, o sunucuda çalışan başka hiçbir şey yoktu; saklı yordamlar yoksa sizi yavaşlatamaz;)
Piskvor binadan ayrıldı

5

Katılma olmadan sipariş öğelerini siparişlerle nasıl ilişkilendireceksiniz? İlişkisel veritabanı yönetim sisteminin tüm noktası budur. Birleştirmeler olmadan ilişkisel veri yoktur ve verileri işlemek için metin dosyalarını da kullanabilirsiniz.

Kavramı anlamıyor gibi görünüyor, bu yüzden işe yaramaz görünmelerini sağlamaya çalışıyor. Excel'in bir veritabanı uygulaması olduğunu düşünen aynı kişi. Onu aptalca tokatla ve veritabanları hakkında daha fazla okumasını söyle. Birden çok bağlantı yapmak ve veri çekmek ve C # ile verileri birleştirmek, işleri yapmanın yanlış yoludur.


5

"SQL birleşimleri işe yaramaz" ifadesinin mantığını anlamıyorum. Üzerinde çalışmadan önce verileri filtrelemek ve sınırlamak faydalı mı? Diğer taraftarların da söylediği gibi, veritabanı motorlarının yaptığı budur, iyi oldukları şey olmalıdır.

Belki de tembel bir programcı, tanıdık oldukları teknolojilere bağlı kalacaktır ve teknik olmayan nedenlerle diğer olasılıklardan kaçınacaktır.

Karar vermek için sana bırakıyorum.


5

Bir örneği ele alalım: fatura kayıtlarına sahip bir tablo ve fatura satır öğesi kayıtlarına sahip bir tablo. İstemci sözde kodunu düşünün:

for each (invoice in invoices)
    let invoiceLines = FindLinesFor(invoice)
...

Her biri 10 satırlı 100.000 faturanız varsa, bu kod 1 milyonluk bir tablodan 10 fatura satırı arar ve bunu 100.000 kez yapar. Tablo boyutu arttıkça, seçme işlemlerinin sayısı artar ve her seçme işleminin maliyeti artar.

Bilgisayarlar hızlı olduğundan, binlerce kayıt veya daha az kaydınız varsa iki yaklaşım arasında bir performans farkı göremeyebilirsiniz. Maliyet artışı doğrusaldan daha fazla olduğu için, kayıtların sayısı arttıkça (milyonlarca, diyelim ki), bir fark fark etmeye başlayacaksınız ve veri kümesinin boyutu büyüdükçe fark daha az tolere edilebilir hale gelecektir.

Ancak birleştirme. tablonun dizinlerini kullanır ve iki veri kümesini birleştirir. Bu, ikinci tabloya rasgele N kez erişmek yerine bir kez etkili bir şekilde taradığınız anlamına gelir. Tanımlanmış bir yabancı anahtar varsa, veritabanında dahili olarak depolanan ilgili kayıtlar arasında bağlantılar zaten vardır.

Bunu kendiniz yaptığınızı düşünün. Alfabetik bir öğrenci listeniz ve tüm öğrencilerin not raporlarını içeren bir not defteriniz var (sınıf başına bir sayfa). Defter, öğrencilerin adlarına göre listeyle aynı sırada sıralanır. Nasıl ilerlemeyi tercih edersin?

  1. Listeden bir ad okuyun.
  2. Dizüstü bilgisayarı açın.
  3. Öğrencinin adını bulun.
  4. Bir sonraki öğrenciye veya son sayfaya ulaşıncaya kadar sayfaları çevirerek öğrencinin notlarını okuyun.
  5. Dizüstü bilgisayarı kapatın.
  6. Tekrar et.

Veya:

  1. Not defterini ilk sayfaya açın.
  2. Listeden bir ad okuyun.
  3. Defterteki bu isim için notları okuyun.
  4. Sonuna kadar 2-3. Adımları tekrarlayın.
  5. Dizüstü bilgisayarı kapatın.

5

Klasik bir " daha iyi yazabilirim " davası gibi geliyor . Başka bir deyişle, boynunda bir çeşit acı olarak gördüğü bir şeyi görüyor (SQL'de bir demet birleşim yazıyor) ve "Bunu daha iyi yazabileceğim ve daha iyi performans elde edebileceğime eminim" diyor. Ona, a) daha akıllı ve b) Oracle veya SQL Server optimizasyon kodunda derin diz çökmüş tipik kişiden daha eğitimli olup olmadığını sormalısınız. Oran değil, değil.


3

Kesinlikle yanlış. C # veya Java gibi dillerdeki veri manipülasyonunda kesin artılar olsa da, SQL'in doğası gereği birleşimler veritabanında en hızlıdır.

SQL, verilerle ilgili istatistikleri ayrıntılı olarak saklar ve dizinlerinizi doğru bir şekilde oluşturduysanız, birkaç milyonda çok hızlı bir kayıt bulabilir. Bunun yanı sıra neden veritabanı düzeyinde doğru yapabildiğinizde birleştirme yapmak için tüm verilerinizi C #'a sürüklemek istersiniz?

Yinelenen bir şey yapmanız gerektiğinde C # kullanmanın avantajları devreye giriyor. Her satır için bazı işlevler yapmanız gerekiyorsa, bunu C # içinde yapmak daha hızlıdır, aksi takdirde veriye katılmak DB'de optimize edilir.


3

Ben daha hızlı sorgu kırma ve kod birleşimler yapıyor bir durumda koştum diyecekler. Bununla birlikte, bunu yapmak zorunda olduğum sadece MySQL'in belirli bir sürümü ile oldu. Diğer her şey, veritabanı muhtemelen daha hızlı olacaktır (sorguları optimize etmeniz gerekebilir, ancak yine de daha hızlı olacaktır).


3

Hangi veritabanlarının kullanılması gerektiği konusunda sınırlı bir görüşe sahip olduğundan şüpheleniyorum. Performansı en üst düzeye çıkarmak için bir yaklaşım, tüm veritabanını belleğe okumaktır. Bu durumda, daha iyi performans elde edebilirsiniz ve verimlilik için bellek varsa birleştirmeler yapmak isteyebilirsiniz. Ancak bu gerçekten bir veritabanı IMHO olarak bir veritabanı kullanmıyor.


3
Çoğu veritabanı motoru bunu sizin için perde arkasında yapacak; ve örneğin MySQL'de tamamen bellek içi bir tablo ( MEMORYmotor) oluşturabilirsiniz. Veritabanı işlevselliğini veritabanı olmadan yeniden uygulamak genellikle ciddi bir NIH
vakasının işaretidir

@phoog: Burada icat edilmedi - başka bir deyişle, "Bunu düşünmedim, bu yüzden yok". Bu nedenle birçok kare tekerlek yeniden icat edildi. (ve evet, bazen tekerleği yeniden icat etmek faydalıdır, örneğin yarış arabaları yapıyorsanız; "sadece" size daha iyi bir tekerlek
getirme

Başka bir deyişle, "Ben bunu yapmadım, bu yüzden çöp olmalı". Bu sadece "Ben test etmedim, bu yüzden benim amacım için uygun olmayabilir" kadar bir doğruluk payı vardır, bu yüzden yargılamadan önce test edin.
Peter Lawrey

@Piskvor: Veri tabanı sadece üzerinde çalıştığı sistemin belleğini kullanabilirken, uygulama uygulama sunucusunun belleğini kullanabilir. Farklı bir şekilde koyun: Veritabanı ayrılmış bir ana bilgisayardaysa, bu önbelleğe erişmek için ağ bant genişliği gerekir ve ağ gecikmesine tabidir, ancak uygulamanın sakladığı tüm önbellekler düşük bellek erişimi gecikmesi hızıyla sorgulanabilir.
meriton

2

Hayır, birleştirmeler yalnızca geçici C # / Java veritabanı kodunda daha iyi optimize edilmez; ancak genellikle daha iyi performans sağlayan birkaç filtreleme tekniği uygulanabilir.


2

Yanılıyor, yetkili programcıların kullandığı birleşimler. Önerilen yönteminin daha verimli olduğu birkaç sınırlı durum olabilir (ve muhtemelen bir Documant veritabanı kullanacağımı iç içe geçebilir), ancak herhangi bir aldatıcı veri miktarınız varsa göremiyorum. Örneğin bu sorguyu alın:

select t1.field1 
from table1 t1
join table2 t2 
    on t1.id = t2.id
where t1.field2 = 'test'

Tablo1'de 10 milyon ve tablo2'de 1 milyon kaydınız olduğunu varsayın. Tablo 1'deki kayıtların 9 milyonunun nerede yan tümcesini karşıladığını varsayalım. Sadece 15 tanesinin de table2'de olduğunu varsayın. Eğer düzgün indekslenmişse milisaniye alacak ve sadece 1 sütun veri ile ağ üzerinden 15 kayıt döndürecek bu sql deyimi çalıştırabilirsiniz. Veya 2 sütun veri ile on milyon kayıt gönderebilir ve ağdaki bir sütun veri ile 1 milyon kayıt daha gönderebilir ve bunları web sunucusunda birleştirebilirsiniz.

Ya da elbette veritabanının tüm içeriğini her zaman web sunucusunda tutabilirsiniz, bu da sürekli değişen önemsiz miktarda veri ve veriye sahipseniz sadece saçmadır. İlişkisel veritabanının niteliklerine ihtiyacınız yoksa bir veritabanı kullanmayın. Ama eğer yaparsanız, doğru kullanın.


2

Bu argümanı bir yazılım geliştirici olarak kariyerim boyunca çok sık duydum. Hemen hemen her ifade edildiğinde, iddiayı yapan adamın ilişkisel veritabanı sistemleri, çalışma şekilleri ve bu sistemlerin nasıl kullanılması gerektiği hakkında fazla bilgisi yoktu.

Evet, yanlış kullanıldığında , birleşimler işe yaramaz hatta tehlikeli gibi görünüyor. Ancak doğru şekilde kullanıldığında, veritabanı uygulamasının optimizasyon gerçekleştirmesi ve geliştiricinin doğru sonucu en verimli şekilde almasına "yardımcı olması" için çok fazla potansiyel vardır.

JOINVeritabanını kullanarak veri parçalarının birbiriyle ilişkisini beklediğiniz şekilde anlattığınızı ve bu nedenle veritabanına ne yapmaya çalıştığınız hakkında daha fazla bilgi verdiğinizi ve böylece ihtiyaçlarınızı daha iyi karşılayabileceğinizi unutmayın.

Cevap kesinlikle: Hayır, JOINShiç işe yaramaz!


0

Bu "teknik olarak doğrudur" yalnızca bir durumda uygulamalarda sık kullanılmaz (birleştirmelerdeki tüm tabloların tüm satırları sorgu tarafından döndürüldüğünde). Çoğu sorguda, her tablonun satırlarının yalnızca bir kısmı döndürülür. Veritabanı motoru, istenmeyen satırları ortadan kaldırmak için bazen dizinleri depolayan değerleri kullanabileceği için bazen gerçek satırı okumadan bile dizinleri kullanır. Veritabanı motoru kendisi C, C ++ vb. İle yazılmıştır ve en azından bir geliştirici tarafından yazılan kod kadar etkilidir.


0

Ciddi bir şekilde yanlış anlamadığım sürece, sorudaki mantık çok kusurludur

Her A için B'de 20 satır varsa, A'daki 1000 satır B'de 20k satır anlamına gelir. Eşleştirmeyi içeren 20k satır içeren çok sayıda "AB" tablosu olmadığı sürece B'de sadece 100 satır olamaz. .

Böylece, 100 B satırından 20'sinin her bir A satırıyla eşleştiği hakkında tüm bilgileri almak için AB tablosuna da sahipsiniz. Yani bu ya:

  • 100, 1000 ve 20k satırlık 3 sonuç kümesi ve bir müşteri KATIL
  • 20k sıralı tek bir birleştirilmiş A-AB-B sonuç kümesi

Böylece istemci incelendiğinde "JOIN" herhangi bir değer katıyor. Bu kötü bir fikir değil. Veritabanından belki de bir nesneyi alıyorsam, ayrı sonuç kümelerine ayırmak daha mantıklı olur. Bir rapor türü arama için, bunu neredeyse her zaman bir düzleştireceğim.

Her halükarda, bu büyüklüğün çapraz birleştirilmesinin neredeyse hiç faydası olmadığını söyleyebilirim. Kötü bir örnek.

Bir yere KATILMALISINIZ ve RDBMS bu konuda iyi. Daha iyisini yapabileceğini düşünen herhangi bir müşteri kodu maymunuyla çalışmak istemiyorum.

afterthought:

İstemciye katılmak için DataTables (.net içinde) gibi kalıcı nesneler gerekir. Düzleştirilmiş bir sonuç kümeniz varsa, DataReader gibi daha hafif bir şeyle tüketilebilir. Yüksek hacim = bir veritabanının birleşmesini önlemek için kullanılan çok sayıda istemci kaynağı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.