Bileşik indeksi ne zaman kullanmalıyım?


133
  1. Bir veritabanında ne zaman bileşik dizin kullanmalıyım?
  2. Bileşik indeks kullanarak performans farkı nedir?
  3. Neden bir bileşik dizin kullanmalıyım?

Örneğin, bir homesmasam var:

CREATE TABLE IF NOT EXISTS `homes` (
  `home_id` int(10) unsigned NOT NULL auto_increment,
  `sqft` smallint(5) unsigned NOT NULL,
  `year_built` smallint(5) unsigned NOT NULL,
  `geolat` decimal(10,6) default NULL,
  `geolng` decimal(10,6) default NULL,
  PRIMARY KEY  (`home_id`),
  KEY `geolat` (`geolat`),
  KEY `geolng` (`geolng`),
) ENGINE=InnoDB  ;

Benim ikisi için de bir bileşik dizini kullanmak için mantıklı mı geolatve geolng, öyle ki:

Değiştiriyorum:

  KEY `geolat` (`geolat`),
  KEY `geolng` (`geolng`),

ile:

KEY `geolat_geolng` (`geolat`, `geolng`)

Öyleyse:

  • Neden?
  • Bileşik bir indeks kullanarak performans farkı nedir?

GÜNCELLEME:

Pek çok kişi bunun tamamen yaptığım sorgulara bağlı olduğunu belirttiği için, aşağıda en sık yapılan sorgu şudur:

SELECT * FROM homes
WHERE geolat BETWEEN ??? AND ???
AND geolng BETWEEN ??? AND ???

GÜNCELLEME 2:

Aşağıdaki veritabanı şemasıyla:

CREATE TABLE IF NOT EXISTS `homes` (
  `home_id` int(10) unsigned NOT NULL auto_increment,
  `primary_photo_group_id` int(10) unsigned NOT NULL default '0',
  `customer_id` bigint(20) unsigned NOT NULL,
  `account_type_id` int(11) NOT NULL,
  `address` varchar(128) collate utf8_unicode_ci NOT NULL,
  `city` varchar(64) collate utf8_unicode_ci NOT NULL,
  `state` varchar(2) collate utf8_unicode_ci NOT NULL,
  `zip` mediumint(8) unsigned NOT NULL,
  `price` mediumint(8) unsigned NOT NULL,
  `sqft` smallint(5) unsigned NOT NULL,
  `year_built` smallint(5) unsigned NOT NULL,
  `num_of_beds` tinyint(3) unsigned NOT NULL,
  `num_of_baths` decimal(3,1) unsigned NOT NULL,
  `num_of_floors` tinyint(3) unsigned NOT NULL,
  `description` text collate utf8_unicode_ci,
  `geolat` decimal(10,6) default NULL,
  `geolng` decimal(10,6) default NULL,
  `display_status` tinyint(1) NOT NULL,
  `date_listed` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `contact_email` varchar(100) collate utf8_unicode_ci NOT NULL,
  `contact_phone_number` varchar(15) collate utf8_unicode_ci NOT NULL,
  PRIMARY KEY  (`home_id`),
  KEY `customer_id` (`customer_id`),
  KEY `city` (`city`),
  KEY `num_of_beds` (`num_of_beds`),
  KEY `num_of_baths` (`num_of_baths`),
  KEY `geolat` (`geolat`),
  KEY `geolng` (`geolng`),
  KEY `account_type_id` (`account_type_id`),
  KEY `display_status` (`display_status`),
  KEY `sqft` (`sqft`),
  KEY `price` (`price`),
  KEY `primary_photo_group_id` (`primary_photo_group_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=8 ;

Aşağıdaki SQL'i kullanarak:

EXPLAIN SELECT  homes.home_id,
                    address,
                    city,
                    state,
                    zip,
                    price,
                    sqft,
                    year_built,
                    account_type_id,
                    num_of_beds,
                    num_of_baths,
                    geolat,
                    geolng,
                    photo_id,
                    photo_url_dir
            FROM homes
            LEFT OUTER JOIN home_photos ON homes.home_id = home_photos.home_id
                AND homes.primary_photo_group_id = home_photos.home_photo_group_id
                AND home_photos.home_photo_type_id = 2
            WHERE homes.display_status = true
            AND homes.geolat BETWEEN -100 AND 100
            AND homes.geolng BETWEEN -100 AND 100

EXPLAIN şunu döndürür:

id  select_type  table        type  possible_keys                                    key                  key_len  ref     rows  Extra
----------------------------------------------------------------------------------------------------------
1   SIMPLE       homes        ref   geolat,geolng,display_status                     display_status       1        const   2     Using where
1  SIMPLE        home_photos  ref   home_id,home_photo_type_id,home_photo_group_id   home_photo_group_id  4        homes.primary_photo_group_id   4  

EXPLAIN komutunun nasıl okunacağını tam olarak anlamıyorum. Bu iyi mi kötü mü görünüyor? Şu anda, geolat ve geolng için bileşik bir indeks KULLANMIYORUM. Olmalı mıyım?

Yanıtlar:


111

Bundan fayda sağlayan sorgular kullandığınızda bileşik bir dizin kullanmalısınız. Şuna benzeyen bileşik bir dizin:

index( column_A, column_B, column_C )

bu alanları birleştirme, filtreleme ve bazen de seçim için kullanan bir sorguya fayda sağlayacaktır. Ayrıca, bu bileşikte en soldaki sütun alt kümelerini kullanan sorgulara da fayda sağlayacaktır. Dolayısıyla, yukarıdaki dizin aynı zamanda ihtiyaç duyulan sorguları da

index( column_A, column_B, column_C )
index( column_A, column_B )
index( column_A )

Ancak ihtiyaç duyan sorgular için yardımcı olmayacaktır (en azından doğrudan değil, daha iyi indeksler yoksa kısmen yardımcı olabilir)

index( column_A, column_C )

Sütun_B'nin nasıl eksik olduğuna dikkat edin.

Orijinal örneğinizde, iki boyut için bir bileşik dizin, çoğunlukla her iki boyutu veya en soldaki boyutu kendi başına sorgulayan sorgulardan yararlanır, ancak en sağdaki boyutu kendi başına sorgulamaz. Her zaman iki boyutu sorguluyorsanız, gitmenin yolu birleşik bir dizindir, hangisinin ilk olduğu önemli değildir (büyük olasılıkla).


1
Mark, orijinal gönderimi güncelledim (güncelleme 2). Bu benim asıl sorgum. Gerçek db şemam. Ve EXPLAIN komutunun döndürdüğü şey. Yani, bu bilgilerle - birleşik bir dizin kullanmalı mıyım? Hâlâ net değilim. Şimdiden teşekkürler.
Teddy

İşaretleyin, cevabınızdaki bileşik indeks, indeksi (sütun_C) karşılıyor mu?
Boris D. Teoharov

Sorunuzu anladığımdan emin değilim. Ancak, dizinin (A, B, C) C sütununda filtreleme yapan bir sorguya yardımcı olup olmayacağını soruyorsanız, yanıt genellikle hayır olur, filtreleme için dizini kullanmaz. Ancak, yalnızca ABC'nin bir alt kümesini seçiyorsanız, tablo taramasını ortadan kaldırmak için dizini kullanabilir. Yani, bu farklı ama ilişkili. Ancak filtrelemeyi etkinleştirmek için dizinlerin tipik kullanımları için cevap hayırdır.
Mark Canlas

1
-1 çünkü bileşik bir indeks yardımcı olmazWHERE geolat BETWEEN ??? AND ??? AND geolng BETWEEN ??? AND ??? . İlk alandan sonra duracaktır. "Soru Taşması" nın cevabı nedenini açıklıyor.
Rick James

1
@felwithe MySQL, bir sorgudaki tabloların her biri için yalnızca bir dizin kullanabilir (Muafiyetler vardır. Örneğin, dizinlerin birleştirilmesi). Bu ideal olarak, bir sorgudaki bir tablonun tüm where-clause, table join, group-by ve order-by için tek bir dizin kullanması gerektiği anlamına gelir. Dolayısıyla her sütunda ayrı bir dizin her zaman çalışmayabilir, ancak bileşik bir dizin sihri yapabilir.
AKHIL MATHEW

57

Aşağıdaki üç sorgunuz olduğunu hayal edin:

Sorgu I:

SELECT * FROM homes WHERE `geolat`=42.9 AND `geolng`=36.4

Sorgu II:

SELECT * FROM homes WHERE `geolat`=42.9

Sorgu III:

SELECT * FROM homes WHERE `geolng`=36.4

Sütun başına ayrı dizininiz varsa, üç sorgu da dizinleri kullanır. MySQL'de, bileşik dizininiz ( geolat, geolng) varsa, yalnızca sorgu I ve sorgu II (bileşik dizinin ilk bölümünü kullanan) dizinleri kullanır. Bu durumda, sorgu III tam tablo araması gerektirir.

On Çoklu-Kolon Endeksleri manuel bölümünde, ben manuel yeniden yazmak istemiyorum bu yüzden çoklu kolon endeksleri, nasıl çalıştığını açıkladı açıkça edilir.

Gönderen MySQL Referans El Kitabı sayfa :

Çok sütunlu bir dizin , dizinlenmiş sütunların değerleri birleştirilerek oluşturulan değerleri içeren sıralı bir dizi olarak kabul edilebilir .

Coğrafi konum ve coğrafi konum sütunları için ayrı indeks kullanırsanız, tablonuzda bağımsız olarak arama yapabileceğiniz iki farklı indeksiniz olur.

INDEX geolat
-----------
VALUE RRN
36.4  1
36.4  8
36.6  2
37.8  3
37.8  12
41.4  4

INDEX geolng
-----------
VALUE RRN
26.1  1
26.1  8
29.6  2
29.6  3
30.1  12
34.7  4

Bileşik dizin kullanıyorsanız, her iki sütun için yalnızca bir dizininiz olur:

INDEX (geolat, geolng)
-----------
VALUE      RRN
36.4,26.1  1
36.4,26.1  8
36.6,29.6  2
37.8,29.6  3
37.8,30.1  12
41.4,34.7  4

RRN göreceli kayıt numarasıdır (basitleştirmek için ID diyebilirsiniz). İlk iki indeks ayrı olarak oluşturulur ve üçüncü indeks bileşiktir. Gördüğünüz gibi, geolat tarafından indekslendiği için kompozit bir üzerinde coğrafi konumlandırmaya dayalı arama yapabilirsiniz, ancak geolat veya "geolat AND geolng" ile arama yapmak mümkündür (geolng ikinci seviye indeks olduğundan).

Ayrıca, MySQL Dizinleri Nasıl Kullanır kılavuzu bölümüne bir göz atın .


1
Aslında, bu soruların hiçbirine sahip değilim. Sorgum orijinal gönderide listelenmiştir. Sorgum evleri bir kare ızgara içinde döndürmek. Uzamsal hakkında bilgim var ve mesafeleri hesaplamaya çalışmıyorum. Belirli bir coğrafi ızgaradaki (ör. Mahalle / şehir / ilçe) tüm evleri görüntülemeye çalışırken bileşik bir indeks kullanmanın mantıklı olup olmadığını bilmek istiyorum
Teddy

Eyazici, orijinal yazımı güncelledim (güncelleme 2). Bu benim asıl sorgum. Gerçek db şemam. Ve EXPLAIN komutunun döndürdüğü şey. Yani, bu bilgilerle - birleşik bir dizin kullanmalı mıyım? Hâlâ net değilim. Şimdiden teşekkürler
Teddy

@ "Aslında, bu sorguların hiçbirine sahip değilim.". Aslında, temel mantığı açıklamak için basit WHERE koşulunu kullandım. Bir sütun üzerinde koşullu (yani WHERE) kullanırken, MySQL mümkün olduğunda indeksleri kullanmaya çalışır. "x ARASI a VE b", "x> a VE x <b" ye benzer. Koşullu sorgunuzda hem coğrafi hem de coğrafi sütun kullandınız. Bileşik indeks "(coğrafi konum, coğrafi konum)" kullanıyorsanız "VE ??? VE ???" ARASINDAKİ geoling koşullu dizinin avantajlarını sağlamaz (bu MySQL içindir). Yani gerektiğini senaryonuz için kolon başına ayrı bir dizin kullanır.
Emre Yazıcı

Ben anlamıyorum HER ZAMAN her iki sütunu da içeren bir sorgu gerçekleştirdiğimde coğrafi konum ve konum belirleme için neden ayrı dizinler kullanmalıyım
Teddy

1
Hayır. Bir "aralık" ile karşılaşıldığında (olduğu gibi BETWEEN), dizinin başka alanları dikkate alınmaz! Yani bileşik indeks daha iyi değil.
Rick James

19

Bileşik endeksin ne işe yaradığı konusunda bir yanlış anlama olabilir. Pek çok kişi where, sizin durumunuzda geolatve durumunda, yan tümce dizine alınmış sütunları kapsadığı sürece bir arama sorgusunu optimize etmek için bileşik dizinin kullanılabileceğini düşünür geolng. Daha derine inelim:

Evlerin koordinatları hakkındaki verilerinizin rastgele ondalık sayılar olacağına inanıyorum:

home_id  geolat  geolng
   1    20.1243  50.4521
   2    22.6456  51.1564
   3    13.5464  45.4562
   4    55.5642 166.5756
   5    24.2624  27.4564
   6    62.1564  24.2542
...

O zamandan beri geolatve geolngdeğerler kendini pek tekrar etmez. Bir bileşik indeks üzerinde geolatve geolngşunun gibi görünür:

index_id  geolat  geolng
   1     20.1243  50.4521
   2     20.1244  61.1564
   3     20.1251  55.4562
   4     20.1293  66.5756
   5     20.1302  57.4564
   6     20.1311  54.2542
...

Bu nedenle bileşik endeksin ikinci sütunu temelde işe yaramaz ! Bileşik bir dizinle sorgunuzun hızı, muhtemelen yalnızca geolatsütundaki bir dizine benzer olacaktır .

Will tarafından belirtildiği gibi, MySQL uzamsal uzantı desteği sağlar. Uzamsal bir nokta, iki ayrı sütun yerine tek bir sütunda saklanır lat lng. Uzamsal indeks böyle bir sütuna uygulanabilir. Ancak, kişisel deneyimlerime göre verimlilik abartılabilir. Uzamsal indeksin iki boyutlu sorunu çözmemesi, sadece ikinci dereceden bölmeli R-Trees kullanarak aramayı hızlandırması olabilir .

Değiş tokuş, bir uzamsal noktanın koordinatları depolamak için sekiz baytlık çift duyarlıklı sayılar kullandığından çok daha fazla bellek tüketmesidir . Eğer Yanlışsam beni düzelt.


5

Bileşik dizinler şu şekilde çok güçlüdür:

  • Yapı bütünlüğünü zorunlu kılın
  • FILTERED id'de sıralamayı etkinleştir

YAPI BÜTÜNLÜĞÜNÜ GÜÇLENDİRİN

Bileşik dizinler yalnızca başka bir dizin türü değildir; Birincil Anahtar olarak bütünlüğü zorlayarak bir tabloya GEREKLİ yapıyı sağlayabilirler.

Mysql's Innodb, kümelemeyi destekler ve aşağıdaki örnek, bir bileşik dizinin neden gerekli olabileceğini göstermektedir.

(Yani bir sosyal ağ için) bir arkadaş tabloları oluşturmak için biz 2 sütunlar gereklidir: user_id, friend_id.

Masa Yapısı

user_id (medium_int)
friend_id (medium_int)

Primary Key -> (user_id, friend_id)

Dolayısıyla, bir Birincil Anahtar (PK) benzersizdir ve bir bileşik PK oluşturarak Innodb, user_id, friend_idyeni bir kayıt eklendiğinde üzerinde kopya olup olmadığını otomatik olarak kontrol edecektir . friend_id = 2Örneğin , hiçbir kullanıcının 1'den fazla kaydı (ilişki bağlantısı) olmaması gerektiği için bu beklenen davranıştır .

Bileşik bir PK olmadan, bir vekil anahtar kullanarak bu şemayı oluşturabiliriz:

user_friend_id
user_id
friend_id

Primary Key -> (user_friend_id)

Şimdi, yeni bir kayıt eklendiğinde, kombinasyona user_id, friend_idsahip önceki bir kaydın halihazırda mevcut olmadığını kontrol etmemiz gerekecek .

Bu nedenle, bileşik bir indeks yapı bütünlüğünü güçlendirebilir.

FİLTRELİ BİR KİMLİKTE SIRALAMAYI ETKİNLEŞTİR

Bir kayıt kümesini gönderinin zamanına göre (zaman damgası veya tarih saat) sıralamak çok yaygındır. Genellikle bu, belirli bir kimliğe gönderi yapmak anlamına gelir. İşte bir örnek

Tablo User_Wall_Posts (Facebook'un duvar gönderilerinin olup olmadığını düşünün)

user_id (medium_int)
timestamp (timestamp)
author_id (medium_int)
comment_post (text)

Primary Key -> (user_id, timestamp, author_id)

Tüm gönderileri sorgulamak ve bulmak user_id = 10ve yorum gönderilerini timestamp(tarihe) göre sıralamak istiyoruz .

SQL SORGUSU

SELECT * FROM User_Wall_Posts WHERE user_id = 10 ORDER BY timestamp DES

Bileşik PK, Mysql'nin indeksi kullanarak sonuçları filtrelemesini ve sıralamasını sağlar; Mysql'in sonuçları almak için geçici bir dosya veya dosya sıralaması kullanması gerekmeyecek. Bileşik anahtar olmadan bu mümkün olmaz ve çok verimsiz bir sorguya neden olur.

Bu nedenle, bileşik anahtarlar çok güçlüdür ve "Aramak istiyorum, column_a, column_bbu nedenle bileşik anahtarlar kullanacağım. Mevcut veritabanı şemam için, tek anahtarlar kadar çok sayıda bileşik anahtarım var. Göz ardı etmeyin." bir bileşik anahtarın kullanımı!


5

Bileşik dizinler aşağıdakiler için yararlıdır:

  • 0 veya daha fazla "=" cümlesi, artı
  • en fazla bir aralık cümlesi.

Bileşik bir dizin iki aralığı işleyemez . Bunu dizin yemek kitabımda daha ayrıntılı olarak tartışıyorum .

En yakını bul - Soru gerçekten optimizasyonla ilgiliyse

WHERE geolat BETWEEN ??? AND ???
  AND geolng BETWEEN ??? AND ???

o zaman hiçbir dizin her iki boyutu da gerçekten işleyemez.

Bunun yerine, 'kutunun dışında düşünmek' gerekir. Bir boyut bölümleme yoluyla uygulanırsa ve diğeri dikkatlice seçilerek uygulanırsa PRIMARY KEY, biri çok büyük enlem / boylam arama tabloları için önemli ölçüde daha iyi verimlilik elde edebilir. Benim latlng blogum , "en yakını bul" un dünya üzerinde nasıl uygulanacağının ayrıntılarına giriyor. Kodu içerir.

PARTITIONsEnlem aralıkların çizgili. PRIMARY KEYKasten böylece kullanışlı satır aynı blokta olması muhtemel olduğunu boylam ile başlar. Depolanan Bir Rutin order by... limit..., yeterince kahve dükkanına (veya her neyse) sahip olana kadar hedefin etrafındaki 'kareyi' yapmak ve büyütmek için karışık kodu düzenler . Aynı zamanda büyük daire hesaplamalarını ve tarih çizgisi ve kutupları ele alır.

Daha

Başka bir blog yazdım; Enlem / boylam aramaları yapmanın 5 yolunu karşılaştırır: http://mysql.rjweb.org/doc.php/latlng#representation_choices (Yukarıda verilen bağlantıya 5'ten biri olarak atıfta bulunur) Diğer yollardan biri de bu, ve belirli bir durum için en uygun olduklarını belirtir :

INDEX(geolat, geolng),
INDEX(geolng, geolat)

, İki veri her iki sütunlu, ve bu değildir geolat ve geolng tek sütunlu indeksleri olan önemlidir.


1

Siyah ve Beyaz diye bir şey yok, tek beden herkese uyar.

Sorgu iş yükünüzün birinden yararlanacağı durumlarda bileşik bir dizin kullanmalısınız.

Bunu belirlemek için sorgu iş yükünüzün profilini çıkarmanız gerekir.

Sorgular tamamen bu dizinden karşılanabildiğinde bileşik bir dizin devreye girer.

GÜNCELLEME (yayınlanan soruya yanıt olarak): Tablodan * seçerseniz, bileşik dizin kullanılabilir, kullanılmayabilir. Emin olmak için EXPLAIN PLAN'ı çalıştırmanız gerekecek .


Coğrafi konum verileri (enlem ve boylam) için bileşik bir dizin kullanmak mantıklı mı?
Teddy

1
Tamamen o tabloya karşı hangi sorguların yapıldığına bağlıdır.
Mitch Wheat

Orijinal gönderimi, gerçekleştirilen en yaygın sorguyu içerecek şekilde güncelledim. Yukarıyı görmek.
Teddy

1

Uzamsal aramalar yapmak için, coğrafi alanları çok hızlı bir şekilde aramaya izin veren bir R-Ağacı algoritmasına ihtiyacınız vardır . Bu iş için tam olarak ihtiyacınız olan şey.

Bazı veritabanlarında yerleşik uzamsal indeksler vardır. Hızlı bir Google araması MySQL 5'te bunların bulunduğunu gösterir (SQL'inize baktığımda MySQL kullandığınızı tahmin ediyorum).


1

Maddeyi optimize etmek istediğinizde bileşik dizin yararlı olabilir group by(bu makaleye bakın http://dev.mysql.com/doc/refman/5.0/en/group-by-optimization.html ). Lütfen dikkatini ver:

GROUP BY için dizin kullanmanın en önemli ön koşulları, tüm GROUP BY sütunlarının aynı dizinden özniteliklere başvurması ve dizinin anahtarlarını sırayla saklamasıdır (örneğin, bu bir HASH dizini değil, bir BTREE dizinidir)


GROUP BYbahsedilmedi.
Rick James

Nerede bahsedilmedi? :) Bahsettiğim yazıda belli ki bahsediliyor. Ve sorulan sorulara cevap veriyor: Bir veritabanında ne zaman bileşik indeks kullanmalıyım? Bileşik indeks kullanarak performans farkı nedir? Neden bir bileşik dizin kullanmalıyım?
Alexander

Düzeltme: GROUP BYOP tarafından bahsedilmedi.
Rick James

Elbette, cevap buydu - bir veritabanında bileşik dizin kullanacağımız durumlardan biri.
Alexander

0

@Mitch ile birlikteyim, tamamen sorgularınıza bağlıdır. Neyse ki istediğiniz zaman dizin oluşturabilir ve bırakabilirsiniz ve sorgu analizcisinin dizinleri kullanıp kullanmadığını görmek için EXPLAIN anahtar sözcüğünü sorgularınızın başına ekleyebilirsiniz.

Tam bir enlem / boylam çifti arayacaksanız, bu endeks muhtemelen mantıklı olacaktır. Ancak muhtemelen belirli bir yere belirli bir mesafedeki evleri arayacaksınız, bu nedenle sorgularınız şuna benzer ( kaynağa bakın ):

select *, sqrt(  pow(h2.geolat - h1.geolat,  2) 
               + pow(h2.geolng - h1.geolng, 2) ) as distance
from homes h1, homes h2
where h1.home_id = 12345 and h2.home_id != h1.home_id
order by distance

ve dizin büyük olasılıkla hiç yardımcı olmayacaktır. Jeo-uzamsal sorgular için bunun gibi bir şeye ihtiyacınız var .

Güncelleme: bu sorgu ile:

SELECT * FROM homes
WHERE geolat BETWEEN ??? AND ???
AND geolng BETWEEN ??? AND ???

Sorgu analizcisi, yalnızca coğrafi konum üzerinde bir dizin veya yalnızca coğrafi konumlandırmada bir dizin veya muhtemelen her iki dizinde de bir dizin kullanabilir. Bileşik bir indeks kullanacağını sanmıyorum. Ancak bu permütasyonların her birini gerçek bir veri kümesi üzerinde denemek ve sonra (a) EXPLAIN'in size ne söylediğini görmek ve (b) sorgunun gerçekte ne kadar süreceğini ölçmek kolaydır.


Evlere kare bir ızgara içinde dönmek istemeyi kullanıyorum. Uzamsal hakkında bilgim var, bu yüzden mesafeyi hesaplamaya çalışmıyorum. Sadece kare ızgara içindeki evleri geri dönmek istiyorum ve bunun hızlı bir şekilde gerçekleşmesini istiyorum. Bu nedenle, dizinlerimin doğru şekilde kurulduğundan emin olmak istiyorum. Bu yardımcı olur mu?
Teddy
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.