MySQL Endeksleme VarChar


10

Daha blogentriesiyi performans için veritabanımı dizine eklemeye çalışıyorum, ancak bir sorun buldum.

İşte yapı:

CREATE TABLE IF NOT EXISTS `blogentries` (
  `id_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `title_id` varchar(100) COLLATE latin1_german2_ci NOT NULL,
  `entry_id` varchar(5000) COLLATE latin1_german2_ci NOT NULL,
  `date_id` int(11) NOT NULL,
  PRIMARY KEY (`id_id`)
)
ENGINE=MyISAM
DEFAULT CHARSET=latin1
COLLATE=latin1_german2_ci
AUTO_INCREMENT=271;

Aşağıdaki gibi bir sorgu dizini düzgün kullanır:

EXPLAIN SELECT id_id,title_id FROM blogentries ORDER by id_id DESC
+ ---- ------------- + + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +
| id | select_type | masa | türü | olası_anahtarlar | anahtar | key_len | ref | satırlar | Ekstra |
+ ---- ------------- + + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +
| 1 | BASİT | blog girişleri | endeksi | NULL | BİRİNCİL | 114 | NULL | 126 | Dizin kullanma |
+ ---- ------------- + + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +

Ben eklemek Ancak, entry_idiçine SELECTsorguda o filesort kullanır

EXPLAIN SELECT id_id,title_id,entry_id FROM blogentries ORDER by id_id DESC
+ ---- ------------- + + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- +
| id | select_type | masa | türü | olası_anahtarlar | anahtar | key_len | ref | satırlar | Ekstra |
+ ---- ------------- + + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- +
| 1 | BASİT | blog girişleri | TÜM | NULL | NULL | NULL | NULL | 126 | Filesort kullanma |
+ ---- ------------- + + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- +

Bunun neden olduğunu ve bundan nasıl kaçınabileceğimi merak ediyordum? Nedeniyledir VarCharve bu başka bir şeye değiştirilmelidir mi?

Tüm sorgularım yüksek Handler_read_rndve Handler_read_rnd_nextdeğerlere koşuyorum olarak dizini kullanmak için çalışıyorum .

Başka bir bilgiye ihtiyacınız varsa ben de gönderebilirim.


filesort, diskte sıralama gerçekleştirdiği anlamına gelir.
Kermit

WHERE 1=1İkinci sorgunuza eklemeyi deneyin .
Kermit

MySQL'in hangi sürümü bu? Sıralama arabellek boyutunuz ( SELECT @@sort_buffer_size) nedir?

@njk filesort, sorgunun 'ORDER BY' kısmının bir sonucudur

1
@TashPemhiwa Mutlaka ilk ifadeye bakınız.
Kermit

Yanıtlar:


6

Eğer bir olmadığı için WHEREya sorguda maddesini ben kullanılması veya endeksi dışı kullanımının bu örneklerde performansı üzerinde çok az etkisi olacağını düşünürdüm, eğer her iki durumda da tüm satırları iade ediyoruz.


Şüphesiz MySQL ORDER BY?
eggyal

@eggyal Bellek için çok büyükse değil.
Kermit

@njk: Bu hiç mantıklı değil ... Her şeyi belleğe yüklemeye gerek kalmadan dizini geçebilir. Sonuçlar, fileort uygulamasına gerek kalmadan sıralanır.
eggyal

@eggyal boyutunu sorgularım varchar(5000).
Kermit

@njk: Ancak bu sütun ne dizinde ne de sıralamada kullanılmıyor.
eggyal

2

ORDER BYOptimizasyon altında belgelendiği gibi :

Kullanılmayan yavaş sorgular için filesort, max_length_for_sort_dataa tetiklemeye uygun bir değere indirmeyi deneyin filesort.

Peter Zaitsev, tam olarak read_rnd_buffer_size adlı makalesinde şunları açıklıyor:

Benim için bu, MySQL 4.1'den bu yana, bu seçenek dar durumlarda kullanılır - eğer birkaç alan alırsanız ( max_length_for_sort_data'dan daha az ) verilerin sıralama arabelleğinde ve sıralama dosyasında saklanması gerekir, böylece seçilen sütunlar read_rnd_buffer'a gerek kalmaz bu nedenle max_length_for_sort_data değerinden daha uzun olduklarından, bunlar arasında bazı TEXT / BLOB sütunları olduğu anlamına gelir. Bununla birlikte, çok sayıda sütun varsa veya uzun VARCHAR sütunları kullanılıyorsa - statik sunumunda max_length_for_sort_data'dan daha uzun bir satır oluşturmak için yalnızca birkaç UTF8 VARCHAR (255) gerekir .

Bu, max_length_for_sort_databirisinin seçtiği sütunların toplam boyutu için bir sınır olduğunu ve filesortbunun üzerinde dizin tabanlı sıralama yerine a kullanılacağını gösterir.

Sizin durumunuzda, entry_id(5002 bayt) seçimi, bu değişkenin 1 KB varsayılan değerinin toplam boyutunu alır ve bu nedenle filesortkullanılır. Sınırı 8 KB'ye çıkarmak için şunları yapabilirsiniz:

SET SESSION max_length_for_sort_data = 8192;

Bu tabloya çok benzer bir kurulum ile bir tablo var ve bu ayar dosya sıralamasında herhangi bir değişiklik tetiklemek için görünmüyor.

@muffinista: Bu ilginç. Sanırım bu diğer RofferMySQLDBA yanıtı başına diğer tampon ayarları ile ilgili olabilir ?
eggyal

2

Burada birçok ilginç yanıt aldınız, ancak kimse soruyu tam olarak cevaplamadı - bu neden oluyor? Anladığım kadarıyla, bir SELECT sorgusu MySQL'de değişken uzunluklu veriler içerdiğinde ve istenen sütunların TÜMÜ ile eşleşen bir dizin olmadığında, her zaman bir dosya dizini kullanır. Verilerin boyutu burada son derece alakalı değildir. MySQL belgelerinde bu soruya doğrudan bir cevap bulmak zor, ancak burada birisinin kendinize çok benzer bir sorun yaşadığı iyi bir blog yazısı var .

Ayrıca bkz: MySQL Sorgularını Optimize Etmek için 10 İpucu (Bu berbat değil) .

Yani, eğer input_id üzerinde bir indeks varsa, o zaman onu ekleyebilir ve hepsi ayarlanabilir. Ama bunun bir seçenek olduğundan şüpheliyim, ne yapmalı?

Bu konuda bir şey yapmanız gerekip gerekmediği ayrı bir sorudur. MySQL'de 'filesort' adının kötü adlandırıldığını bilmek önemlidir - bu yalnızca belirli bir sorguyu sıralamak için kullanılan algoritmanın adıdır ve birçok durumda sıralama aslında bellekte gerçekleşir. Bu tablonun çok fazla büyümesini beklemiyorsanız, muhtemelen büyük bir sorun değil.

Öte yandan, bu tablonun içinde bir milyon satır olacaksa, bir sorununuz olabilir. Bu tablodaki sorguların sayfalandırılmasını desteklemeniz gerekiyorsa, burada gerçekten ciddi bir performans sorununuz olabilir. Bu durumda, değişken uzunluktaki verilerinizi yeni bir tabloya bölmek ve almak için JOIN yapmak dikkate alınması gereken geçerli bir optimizasyondur.

İşte SO'da bu soru hakkında konuşan birkaç cevap daha:


OP'nin ilk sorgusu " MySQL'de değişken uzunluklu veriler içeriyor ve istenen sütunların TÜMÜ ile eşleşen bir dizin yok ", ancak filesortgörünüşe göre bu durumda kullanılmadı. Ben bile sadece bellekte küçük bir tablo sıralama bile kabul edilemez bir performans hit olduğunu düşünüyorum: örneğin sorgu çok yapılır (ve tablo önbellek kullanılamaz böylece değişir).
eggyal

Test etmek için zamanım yok, ancak bunun dev.mysql.com/doc/refman/5.1/en/char adresinde belirtilen uzunluğu depolamak için 2 bayt gerektiren bir VARCHAR'a sahip olup olmadığını merak ediyorum . html - ilk sorgu bu sınıra sığar ancak ikincisi uymaz.

0

WHERESorgularınıza bir cümle eklemeyi deneyin .

Dizin , kullanılmayan bölümlerin tümü ve tüm fazladan ORDER BY sütunları WHERE yan tümcesinde sabit olduğu sürece , ORDER BY dizinle tam olarak eşleşmese bile kullanılabilir . Bazı durumlarda, WHERE yan tümcesiyle eşleşen satırları bulmak için yine de dizinleri kullanmasına rağmen , MySQL ORDER BY'ı çözümlemek için dizinleri kullanamaz .

http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html


Ancak bu durumda ORDER BY yapar tam endeksi eşleşmesi, bu nedenle bir olması gerek yoktur WHEREmaddesini.
eggyal

Sitede gerçek sorgu bir "nerede" yan tümcesi var, bu yüzden dosya sıralama nedeni thats biliyorum. Ben varchar kullanımı olup olmadığını merak ediyorum?

0

Bildiğim kadarıyla varchar en fazla 8000 bayt tutabilir ki bu yaklaşık 4000 karakterdir. Böylece, 5000'in depolama sınırını aştığı görülüyor ve bu durumda muhtemelen sıralamanın dağılmasının nedeni.

"varchar [(n | max)] Değişken uzunlukta, Unicode olmayan karakter verileri. n, 1 ile 8.000 arasında bir değer olabilir. max, maksimum depolama boyutunun 2 ^ 31-1 bayt olduğunu gösterir. Depolama boyutu gerçek Girilen verinin uzunluğu + 2 bayt. Girilen veriler 0 karakter uzunluğunda olabilir. Varchar için SQL-2003 eş anlamlıları karakter veya karakter değişkendir. "

Umarım bu soruya cevap verir


Altında belgelendiği gibi The CHARve VARCHARTürleri : " VARCHAR sütunları değerler değişken uzunluklu dizeleri uzunluğu 5.0.3 ve sonraki sürümlerinde 65.535 MySQL 5.0.3 öncesi 0 ile 255 arasında bir değer olarak belirtilir ve 0 edilebilir etkili.. VARCHARMySQL 5.0.3 ve sonraki sürümlerde maksimum uzunluğu , maksimum satır boyutuna (tüm sütunlar arasında paylaşılan 65.535 bayt) ve kullanılan karakter kümesine
tabidir

0

Masanızda yalnızca 126 satır var. Her satır maksimum 5 KB boyutunda olsa bile, bu diskten okunacak toplam boyutun sadece 600 KB olduğu anlamına gelir - bu bir sürü değildir. Açıkçası, çoğu modern disk sürücüsünün önbellek boyutundan daha az, çok küçük bir miktardır.

Şimdi, sunucunun sorgunuzu yerine getirmek için verilerinizi alması gerekiyorsa, en pahalı işlem onu ​​diskten okumaktır. Ancak, dizin sırasına göre okumak, özellikle veri miktarı çok küçük olduğunda, bunu yapmak için her zaman en hızlı yol değildir.

Sizin durumunuzda, diskten tüm tablo verilerini tek blok olarak belleğe (muhtemelen sadece bir disk okuma işleminde veya aramasında) okumak ve daha sonra diske kıyasla anlık olan ORDER BY'ı karşılamak için RAM'de sıralamak çok daha verimlidir. okuma işlemi. Sunucu verilerinizi dizine göre okursa, aynı veri dosyasında birçok kez ileri ve geri arama yaparak 126 (ay!) Okuma işlemi gerçekleştirmesi gerekir.

Başka bir deyişle, sıralı tarama her zaman kötü bir şey DEĞİLDİR ve mysql mutlaka aptal değildir. Mysql'yi bu dizini kullanmaya zorlarsanız, büyük olasılıkla şu anda sahip olduğunuz sıralı taramadan daha yavaş çalışır.

Ve 5KB alanı dahil edilmediğinde indeks kullanma nedeninin nedeni, alınan verilerin tablodaki verilerin% 99'unu oluşturmamasıdır. 5KB alanınızı eklediğinizde, sorgunun verilerin% 99'unu okuması gerekir ve her şeyi okumak ve daha sonra bellekte sıralamak daha ucuzdur.


Tam Tablo Taramalardan Nasıl Kaçınılır? Başlıklarından , yan tümceleri değil, tatmin edici JOINkoşullarda ve WHEREcümlelerde dizin kullanımı ile ilgili olan bir çok şeyi karıştırıyor gibi görünüyorsunuz ORDER BY.
eggyal

Tam tersi. Bu özel durumda, tam tablo taraması, dizin sırasına göre okumaktan daha hızlı olduğu için İYİ şeydir.

0

Hangi MySQL sürümünü kullanıyorsunuz?

5.1'de, senaryonuzu kurmaya çalıştım ve kukla veriler doldurdum. Sağladığınız SQL'leri kullanarak, her seferinde EXPLAIN'e göre bir tablo taraması alıyorum. Varsayılan olarak, birincil dizin sıralamada kullanılsa bile, MYSQL tarafından sipariş kullandığınızda filesort'a başvurur.

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.