MySQL tablolarına nasıl indeks ekleyebilirim?


407

Yaklaşık 150.000 satır veri içeren çok büyük bir MySQL masam var. Şu anda, koşmaya çalıştığımda

SELECT * FROM table WHERE id = '1';

Kimlik alanı birincil dizin olduğundan kod düzgün çalışır. Ancak, projede yeni bir gelişme için, başka bir alana göre veritabanı aramak zorunda. Örneğin:

SELECT * FROM table WHERE product_id = '1';

Bu alan önceden dizine eklenmemişti; Ancak, bir ekledim, bu yüzden mysql şimdi alan indeksler, ancak yukarıdaki sorguyu çalıştırmaya çalıştığınızda, çok yavaş çalışır. Bir EXPLAIN sorgusu, zaten bir tane eklediğimde product_id alanı için bir dizin olmadığını ve bunun sonucunda sorgunun tek bir satır döndürmek için 20 dakika ile 30 dakika arasında sürdüğünü gösterir.

Tüm EXPLAIN sonuçlarım:

| id | select_type | table | type | possible_keys| key  | key_len | ref  | rows  | Extra       |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+
|  1 | SIMPLE      | table | ALL  | NULL         | NULL | NULL    | NULL |157211 | Using where |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+

Bir göz attığımı ve ID alanının INT olarak, PRODUCT_ID alanının da VARCHAR olarak depolandığını not etmek yararlı olabilir. Sorunun kaynağı bu olabilir mi?


1
Tüm EXPLAINsonuçları gönderebilir misiniz ? Emin misiniz onun orada işte hiçbir indeks? Veya dizin orada, ama MySQL onu kullanmamayı mı tercih ediyor?
VoteyDis Policy

169
Büyük bir tablonun 150.000.000 kaydı olurdu. Çok büyük bir tabloda 15.000.000.000 kayıt vardır. Ortalama büyüklükte bir tablo 150.000'dir. İleride başvurmak için.
usumoio

4
'VEYA' seçeneğinin MySql'in dizin kullanmamasını sağlayabileceğini unutmayın. 3 VEYA ile bir sorgu vardı. Her biri bir indeks işledi ve 15ms'de koştu, Hepsi birlikte 25 saniye ile zaman aşımı sürdü. Bu yüzden 3 sorgu yaptım ve onları bir araya getirdim, 500.000 satırda 15ms aldı.
Leif Neland

Sakladığınız veri türünü göz önünde bulundurun. Performans, karşılaştırdığınız veri türünüze göre değişebilir. Dediğiniz gibi PRODUCT_ID bir VARCHAR veri türüdür, INT olarak değiştirmeyi deneyin ve sütunu endeksleyin.
gilbertdim

Yanıtlar:


606
ALTER TABLE `table` ADD INDEX `product_id_index` (`product_id`)

Hiçbir zaman karşılaştırmak integeriçin stringsMySQL. Öyleyse id, inttırnak işaretlerini kaldırın.


Zaten tam SQL kullanarak dizin ekledim ama veri "uygulanmadı" gibi görünüyor ve EXPLAIN sorgu alan için bir dizin olmadığını gösterir.
Michael

1
Dizini bir OLUŞTURMA TABLOSU ile kontrol etmek ister misiniz, yoksa bunu zaten yaptınız mı?
Haziran'da Wrikken

33
Dizinlerin eklenip eklenmediğini kontrol etmek için SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/en/show-index.html adresini kullanın
Timo Huovinen

6
Bugün @Michael açıkladı tam bir sorun vardı ve çözüm "mysql dizeleri tamsayı asla karşılaştırmak" oldu. Teşekkür ederim.
user12345

@ Wrikken Dizinimi ekledim ve ENDEKSLERİNİ GÖSTERİNİZDEN GÖSTER komutunu kullandım. Görünüyor ama masamı sorgularken kullanıldığını sanmıyorum. Bir dizin kullanırken seçme sorgusunu değiştirmem gerekiyor mu?
Ced

148
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);

97
MySQL, kullanmak durumunda ALTER TABLE tbl ADD INDEX (col)yerine ALTER TABLE tbl ADD INDEX col (col)o kullanarak, ALTER TABLE tbl ADD INDEX (col)adlandırılmış endeks eklemeye devam edecektir defadan fazla col_2, col_3... her seferinde. Oysa ALTER TABLE tbl ADD INDEX col (col)2. kez kullanmak , verecektir ERROR 1061 (42000): Duplicate key name 'col'.
Abhishek Oza

82

Bu sözdizimini bir dizin eklemek ve dizin türünü (HASH veya BTREE) kontrol etmek için kullanabilirsiniz.

create index your_index_name on your_table_name(your_column_name) using HASH;
or
create index your_index_name on your_table_name(your_column_name) using BTREE;

BTREE ve HASH dizinleri arasındaki farkları buradan öğrenebilirsiniz: http://dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html


1
Show dizinleri kullandığımda Hash btree'ye dönüştürüldü.
RN Kushwaha

1
Herhangi bir belirtmezsem Hash ve BTree'den varsayılan değer ne olur?
Bhavuk Mathur

2
@RNKushwaha, çünkü InnoDB ve MyIsam HASH, AFAIK'i desteklemiyor, sadece Memory ve NDB depolama motorları destekliyor
Hieu Vo

60

Birden fazla alan dizininin sorgu performansınızı önemli ölçüde artırabileceğini belirtmek gerekir. Yukarıdaki örnekte, ProductID değerinin aranacak tek alan olduğunu, ancak ProductID = 1 AND Category = 7 demek için sorgu olduğunu varsayarak çoklu sütun dizini yardımcı olur. Bu, aşağıdakilerle elde edilir:

ALTER TABLE `table` ADD INDEX `index_name` (`col1`,`col2`)

Ayrıca dizin, sorgu alanlarının sırasıyla eşleşmelidir. Genişletilmiş örneğimde, dizin başka şekilde değil (ProductID, Category) olmalıdır.


1
Güzel, açıkça indeks adlandırmak kolay tersine izin verir.
Sam Berry

Kaynağını teklif edebilir misiniz the index should match the order of the query fields?
Bishwas Mishra

58

İki tür dizin eklenebilir: Birincil anahtar tanımladığınızda, MySQL bunu varsayılan olarak dizin olarak alır.

açıklama

Dizin olarak birincil anahtar

Bir tbl_studenttablonuz olduğunu ve student_idbirincil anahtar olmasını istediğinizi düşünün :

ALTER TABLE `tbl_student` ADD PRIMARY KEY (`student_id`)

Yukarıdaki ifade birincil anahtar ekler, yani dizinlenmiş değerlerin benzersiz olması ve NULL olamaz.

Dizin adını belirtin

ALTER TABLE `tbl_student` ADD INDEX student_index (`student_id`)

Yukarıdaki ifade student_indexadında sıradan bir dizin yaratacaktır .

Benzersiz dizin oluştur

ALTER TABLE `tbl_student` ADD UNIQUE student_unique_index (`student_id`)

Burada, student_unique_indexstudent_id öğesine atanan dizin adıdır ve değerlerin benzersiz olması gereken bir dizin oluşturur (burada null kabul edilebilir).

Tam metin seçeneği

ALTER TABLE `tbl_student` ADD FULLTEXT student_fulltext_index (`student_id`)

Yukarıdaki ifade, student_fulltext_indexMyISAM Mysql Engine'e ihtiyacınız olan Tam Metin dizin adını oluşturur .

Dizinler nasıl kaldırılır?

DROP INDEX `student_index` ON `tbl_student`

Kullanılabilir dizinler nasıl kontrol edilir?

SHOW INDEX FROM `tbl_student`

17

Bir endeksiniz olduğunu söylüyorsunuz, açıklama aksini söylüyor. Ancak, gerçekten böyle yaparsanız, devam etmek için:

Sütunda bir dizin varsa ve MySQL bunu kullanmamaya karar verirse, bunun nedeni şu olabilir:

  1. MySQL sorgusunda kullanımı daha uygun bulduğu başka bir dizin var ve yalnızca birini kullanabilir. Çözüm, normal geri alma yöntemleri birden fazla sütuna göre birden fazla sütuna yayılan bir dizindir.
  2. MySQL, eşleşen birçok satır olduğuna karar verir ve bir tablecanın muhtemelen daha hızlı olduğunu düşünür. Eğer durum böyle değilse, bazen ANALYZE TABLEyardımcı olur.
  3. Daha karmaşık sorgularda, sorgu planında son derece akıllı düşünülmüş voodoo'ya dayanarak kullanılmamasına karar verir, bazı nedenlerden dolayı mevcut gereksinimlerinize uymaz.

(2) veya (3) durumunda, MySQL'i indeksi indeks ipucu sytax ile kullanmaya koyabilirsiniz , ancak eğer yaparsanız, indeksi ipucu olarak kullanmak için performansı geliştirip geliştirmediğini belirlemek için bazı testler yaptığınızdan emin olun. .

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.