MySQL'de VARCHAR alanında olası INDEX


40

MySQL veritabanında , böyle bir tabloyla çalışıyorum :

+--------------+
|  table_name  |
+--------------+
|    myField   |
+--------------+

... ve bunun gibi çok fazla sorgu yapmam gerekiyor (listede 5-10 karakter var) :

SELECT myField FROM table_name
WHERE myField IN ('something', 'other stuff', 'some other a bit longer'...)

Yaklaşık 24.000.000 benzersiz satır olacak

1) a FULLTEXTveya ve INDEXanahtarını benim için kullanmalı mıyım VARCHAR(150)?
2) Karakterleri 150'den 220'ye veya 250'den arttırırsam ... bu büyük bir fark yaratır mı? (Bunu hesaplamanın bir yolu var mı?)
3) Dediğim gibi, benzersiz olacaklar, bu yüzden myField bir PRIMARY KEY olmalı . Zaten bir VARCHAR INDEX / FULLTEXT olan bir alana bir PRIMARY KEY eklemek nadir değil mi?


benzersiz olması için PRIMARY kullanmanıza gerek yoktur. Bunun için zaten BENZERSİZ var.
kommradHomer

Yanıtlar:


62

ÖNERİ # 1: Standart Endeksleme

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    key (myfield)
);

Bu şekilde dizine eklerseniz, dizenin tamamını arayabilir veya sola dayalı LIKE aramaları yapabilirsiniz.

ÖNERİ # 2: TAM METİN İndeksleme

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    fulltext (myfield)
);

Tek tek anahtar kelimeler için aramaların tümünü ve tüm cümleleri etkili bir şekilde kullanabilirsiniz. Özel bir parola listesi tanımlamanız gerekecek, çünkü MySQL 543 kelimeyi endekslemeyecek .

İşte son iki yıldaki FULLTEXT endekslerindeki diğer yayınlarım

ÖNERİ # 3: Karma İndeksleme

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    hashmyfield char(32) not null,
    primary key (id),
    key (hashmyfield)
);

Belirli bir değer arıyorsanız ve bu değerler 32 karakterden uzun olabilirse, karma değeri saklayabilirsiniz:

INSERT INTO mytable (myfield,hashmyfield)
VALUES ('whatever',MD5('whatever'));

Bu şekilde, sonuçları almak için karma değerleri ararsınız.

SELECT * FROM mytable WHERE hashmyfield = MD5('whatever');

Bir şans ver !!!


Cevabınızı oylayacak kadar itibarım yok ama bunun BÜYÜK olduğunu söylemeliyim. Açıklama ve örnekler için teşekkür ederim. Hash endekslemesinin davam için en iyisi olduğunu düşünüyorum, harika bir çözüm. Ama yine de bir soru: Sizce tablodaki hızlı aramalar için satır limitinin ne olacağını düşünüyorsunuz? [aramalar için VARCHAR (32) KEY tuşunu kullanarak]
Mark Tower

2
Burada karma seçeneği hala bir metin ve gerçekten 16 bayt olan 32 bayt. Bir bigint alanını conv ile kullanabilirsiniz (sol (md5 ('neyse'), 16), 16, -10). 16 baytlık bir sayısal yok, ancak
md5'in

1
Dizine alınacak dizeleri üretmek için MD5 veya SHA1 kullanmak iyi değildir. MD5 veya SHA1 gibi karma fonksiyonlar tarafından üretilen dizgelerin dağılımı, INSERT ve SELECT ifadelerini yavaşlatabilen indeksinizin verimini düşüren geniş bir alanda rastgeledir. İşte bunu açıklayan bir yazı: code-epicenter.com/…
Mr.M

Bu eski bir konu olduğu için özür dilerim, ancak sorum doğrudan bununla ilgili ama yukarıda ve diğer benzer makaleleri okumaktan ihtiyaçlarım için net bir cevap alamıyorum. Senaryom: Şimdilik sadece bir masadan oluşan çok basit bir stok sistemi geliştiriyorum. Bir API üzerinden dışarıdan erişilir, böylece tüm konfigürasyon başka bir yerde tutulur - bu nedenle sadece tek bir masaya ihtiyacımız var. Dizin oluşturmayı düşündüğüm iki sütun, her biri yaklaşık <20 karakter uzunluğunda yaklaşık 200 benzersiz girdi içeriyordu. Dizin eklemeyi düşünmeli miyim?
Mike

Bu sola yönelik arama gibi like 'a%'mi?
Muhasebeci

18

MySQL ön ekli dizini tanımlamanıza izin verir, bu da ilk N karakterini dizine eklenecek orijinal dizeden tanımladığınız anlamına gelir; ve püf noktası, iyi seçicilik sağlayacak kadar uzun, ancak yer kazanmak için yeterince kısa olan bir N sayısını seçmektir. Önek, dizini, tüm sütunu dizine ekleyebildiğiniz kadar kullanışlı hale getirmek için yeterince uzun olmalıdır.

Daha ileri gitmeden önce bazı önemli terimleri tanımlayalım. Dizin seçiciliği , toplam ayrı dizine alınmış değerlerin oranı ve toplam satır sayısıdır . Test tablosu için bir örnek:

+-----+-----------+
| id  | value     |
+-----+-----------+
| 1   | abc       |
| 2   | abd       |
| 3   | adg       |
+-----+-----------+

Yalnızca ilk karakteri indekslersek (N = 1), indeks tablosu aşağıdaki tabloya benzeyecektir:

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| a             | 1,2,3     |
+---------------+-----------+

Bu durumda, indeks seçiciliği IS = 1/3 = 0.33'e eşittir.

Dizine alınmış karakter sayısını ikiye çıkarırsak ne olacağını şimdi görelim (N = 2).

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| ab             | 1,2      |
| ad             | 3        |
+---------------+-----------+

Bu senaryoda IS = 2/3 = 0.66, bu da indeks seçiciliğimizi arttırdığımızı, ancak indeks boyutunu da arttırdığımızı gösteriyor. İşin püf noktası, azami endeks seçiciliği ile sonuçlanacak olan N sayısını bulmaktır .

Veritabanı tablonuz için hesaplamaları yapabileceğiniz iki yaklaşım vardır. Bu veri tabanı dökümü hakkında gösteri yapacağım .

Diyelim ki , masadaki çalışanların son soyadı için endeks sütununu eklemek istiyoruz ve en iyi endeks seçiciliğini üretecek en küçük N sayısını tanımlamak istiyoruz .

İlk önce en sık kullanılan soyadları tanımlayalım:

select count(*) as cnt, last_name from employees group by employees.last_name order by cnt

+-----+-------------+
| cnt | last_name   |
+-----+-------------+
| 226 | Baba        |
| 223 | Coorg       |
| 223 | Gelosh      |
| 222 | Farris      |
| 222 | Sudbeck     |
| 221 | Adachi      |
| 220 | Osgood      |
| 218 | Neiman      |
| 218 | Mandell     |
| 218 | Masada      |
| 217 | Boudaillier |
| 217 | Wendorf     |
| 216 | Pettis      |
| 216 | Solares     |
| 216 | Mahnke      |
+-----+-------------+
15 rows in set (0.64 sec)

Gördüğünüz gibi, soyadı Baba en sık biridir. Şimdi en sık ortaya çıkan soyadı öneklerini beş harfli öneklerden başlayarak bulacağız .

+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa  |
| 758 | Mande  |
| 711 | Schwa  |
| 562 | Angel  |
| 561 | Gecse  |
| 555 | Delgr  |
| 550 | Berna  |
| 547 | Peter  |
| 543 | Cappe  |
| 539 | Stran  |
| 534 | Canna  |
| 485 | Georg  |
| 417 | Neima  |
| 398 | Petti  |
| 398 | Duclo  |
+-----+--------+
15 rows in set (0.55 sec)

Her önekte çok daha fazla sonuç vardır, bu, N sayısının önceki örnektekilerle aynı olana kadar N sayısını arttırmamız gerektiği anlamına gelir.

N = 9 için sonuçlar

select count(*) as cnt, left(last_name,9) as prefix from employees group by prefix order by cnt desc limit 0,15;

+-----+-----------+
| cnt | prefix    |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba      |
| 223 | Coorg     |
| 223 | Gelosh    |
| 222 | Sudbeck   |
| 222 | Farris    |
| 221 | Adachi    |
| 220 | Osgood    |
| 218 | Mandell   |
| 218 | Neiman    |
| 218 | Masada    |
| 217 | Wendorf   |
| 217 | Boudailli |
| 216 | Cummings  |
| 216 | Pettis    |
+-----+-----------+

İşte N = 10 için sonuçlar.

+-----+------------+
| cnt | prefix     |
+-----+------------+
| 226 | Baba       |
| 223 | Coorg      |
| 223 | Gelosh     |
| 222 | Sudbeck    |
| 222 | Farris     |
| 221 | Adachi     |
| 220 | Osgood     |
| 218 | Mandell    |
| 218 | Neiman     |
| 218 | Masada     |
| 217 | Wendorf    |
| 217 | Boudaillie |
| 216 | Cummings   |
| 216 | Pettis     |
| 216 | Solares    |
+-----+------------+
15 rows in set (0.56 sec)

Bu çok iyi sonuçlar. Bu, yalnızca ilk 10 karakteri indeksleyerek son soyadı sütununda indeks yapabileceğimiz anlamına gelir . Tablo tanımı sütununda last_name , olarak tanımlanır VARCHAR(16)ve bu, giriş başına 6 bayt (veya soyadı UTF8 karakterleri varsa) kaydettiğimiz anlamına gelir. Bu tabloda 6 bayt ile çarpılan 1637 farklı değer var, yaklaşık 9KB ve tablomuz milyon satır içeriyorsa bu sayının nasıl artacağını hayal edin.

Sen sayısını hesaplarken başka yollarını okuyabilir N mesajımın içinde MySQL öneki endeksler .

Dizine alınması gereken değerleri üretmek için MD5 ve SHA1 işlevlerini kullanmak da iyi bir yaklaşım değildir . Neden? Yazıyı oku MySQL veritabanında birincil anahtar için doğru veri türü nasıl seçilir


Bu, farklı bir soruya çok ayrıntılı bir cevaptır.
mustaccio

1
Benimle dalga mı geçiyorsun?
Bay

Neyin yanlış olduğunu veya soruya neyin uygulanamayacağını açıklayabilir misiniz?
Bay

2
Selam MrD. Aslında cevabını beğendim. Neden ? Eski cevabımda ÖNEMLİ # 1: 'de dedim If you index like this, you can either look for the whole string or do left-oriented LIKE searches. Ayrıca ÖNERİ 3. söyledi: If you are looking for one specific value and those values could be lengths well beyond 32 characters, you could store the hash value:. Cevabınız, neden birisinin büyük anahtarlar kullanmaması ve performansta fark yaratabilecek en soldaki karakterlere endekslenmesi gerektiğini yeterince göstermektedir. Cevabınız buraya ait. Cevabınız için +1 ve DBA StackExchange'e Hoş Geldiniz.
RolandoMySQLDBA
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.