Можливий INDEX на полі VARCHAR в MySql


40

Я працюю в базі даних MySql зі такою таблицею:

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

... і мені потрібно зробити багато таких запитів (із 5-10 рядків у списку) :

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

Буде близько 24 000 000 унікальних рядів

1) Чи слід використовувати клавішу a FULLTEXTабо INDEXдля свого ключа VARCHAR(150)?
2) Якби я збільшив показники зі 150 до 220 або 250 ... чи це мало би велике значення? (Чи є спосіб , щоб обчислити його?)
3) Як я вже сказав, вони збираються бути унікальним, так MyField має бути PRIMARY KEY . Чи не рідко можна додати ПЕРШИЙ КЛЮЧ до поля, яке вже є VARCHAR INDEX / FULLTEXT?


вам не потрібно використовувати ПРИМІТНИЙ для унікальності. Для цього вже є УНІКАЛЬНИЙ.
kommradHomer

Відповіді:


62

ПРЕДЛОЖЕННЯ №1: Стандартна індексація

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

Якщо індексувати так, ви можете або шукати весь рядок, або робити орієнтовані на ліворуч пошуки LIKE

ПРЕДЛОЖЕННЯ №2: Індексація FULLTEXT

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

Ви можете ефективно використовувати пошук окремих ключових слів, а також цілих фраз. Вам потрібно буде визначити спеціальний список зупинок, оскільки MySQL не індексує 543 слова .

Ось інші мої пости за останні два роки за показниками FULLTEXT

ПРЕДЛОЖЕННЯ №3: Хеш-індексація

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

Якщо ви шукаєте одне конкретне значення, і ці значення можуть бути довжиною значно більше 32 символів, ви можете зберігати хеш-значення:

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

Таким чином, ви просто шукаєте хеш-значення для отримання результатів

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

Спробувати !!!


Я не маю достатньо репутації, щоб проголосувати вашу відповідь, але мушу сказати, що це ВЕЛИКО. Дякую за пояснення та приклади. Я думаю, що хеш-індексація найкраща для мого випадку, це приголомшливе рішення. Але все-таки одне запитання: як ви вважаєте, що буде межа рядків для швидких пошуків у таблиці? [використовуючи як КЛЮЧИТИ ВАРХАР (32) для обшуків]
Марк-вежа

2
Тут опція хеша - це текст і 32 байти для того, що насправді становить 16 байт. Можна використовувати поле bigint з conv (зліва (md5 ('що завгодно'), 16), 16, -10). Там немає 16-байтного числового числа, але ви можете
здати, що

1
Недоцільно використовувати MD5 або SHA1 для створення рядків, які будуть індексовані. Розподіл рядків, що виробляються хеширующими функціями, такими як MD5 або SHA1, є випадковим у великому просторі, що знижує ефективність вашого індексу, що може уповільнити оператори INSERT та SELECT. Ось пост, що пояснює це: code-epicenter.com/…
Mr.M

Прошу вибачення за те, що це стара тема, але моє питання, пов’язане безпосередньо з цим, але я не в змозі отримати чітку відповідь на свої потреби, прочитавши вищезгадані та інші подібні статті. Мій сценарій такий: я розробляю дуже рудиментарну систему акцій, яка наразі складається лише з однієї таблиці. Доступ до нього здійснюється за допомогою API, тому вся конфігурація зберігається в іншому місці - ось чому нам потрібна лише одна таблиця. У двох стовпцях, які я думаю про індексацію, було б приблизно 200 унікальних записів у кожній, довжиною <20 символів. Чи варто розглянути можливість додавання індексів?
Майк

Це ліво-орієнтований, як пошук like 'a%'?
Бухгалтер з

18

MySQL дає змогу визначити попередньо встановлений індекс, що означає, що ви визначаєте перші N символів з початкового рядка для індексації, а хитрість полягає в тому, щоб вибрати число N, яке досить довге, щоб дати гарну вибірковість, але досить коротке, щоб заощадити місце. Префікс повинен бути досить довгим, щоб зробити індекс майже таким же корисним, як це було б, якби ви індексували весь стовпець.

Перш ніж піти далі, давайте визначимося з деякими важливими термінами. Селективність індексу - відношення загальної різної індексованої величини та загальної кількості рядків . Ось один приклад для тестової таблиці:

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

Якщо ми індексуємо лише перший символ (N = 1), то таблиця індексів буде мати вигляд наступної таблиці:

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

У цьому випадку вибірковість індексу дорівнює IS = 1/3 = 0,33.

Давайте тепер подивимося, що буде, якщо збільшимо кількість індексованих символів до двох (N = 2).

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

У цьому сценарії IS = 2/3 = 0,66, це означає, що ми збільшили вибірковість індексу, але також збільшили розмір індексу. Трюк - знайти мінімальне число N, що призведе до максимальної вибірковості індексу .

Існує два підходи, за допомогою яких можна обчислити таблицю бази даних. Я продемонструю на цьому дамп-базі даних .

Припустимо, ми хочемо , щоб додати стовпець last_name в таблиці співробітників до індексу, і ми хочемо , щоб визначити найменше число N , яке буде виробляти кращий показник селективності.

Спершу визначимо найчастіші прізвища:

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)

Як бачите, прізвище Баба є найчастішим. Тепер ми будемо знаходити префікси прізвища, що найчастіше зустрічаються , починаючи з п’яти буквених префіксів.

+-----+--------+
| 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)

У кожному префіксі набагато більше випадків, а це означає, що нам потрібно збільшити число N, поки значення майже не будуть такими ж, як у попередньому прикладі.

Ось результати для N = 9

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    |
+-----+-----------+

Ось результати для N = 10.

+-----+------------+
| 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)

Це дуже хороші результати. Це означає, що ми можемо робити покажчик на прізвище стовпця, індексуючи лише перші 10 символів. У таблиці визначення стовпця прізвище last_name визначається як VARCHAR(16), і це означає, що ми зберегли 6 байтів (або більше, якщо в прізвищі є символи UTF8). У цій таблиці 1637 різних значень, помножених на 6 байт, це приблизно 9 КБ, і уявіть, як зростало б це число, якщо наша таблиця містить мільйон рядків.

Ви можете прочитати інші способи обчислення кількості N у моєму пост Префіксні індекси в MySQL .

Використання функцій MD5 та SHA1 для генерування значень, які слід індексувати, також не є гарним підходом . Чому? Прочитайте його у публікації Як правильно вибрати тип даних для первинного ключа в базі даних MySQL


Це дуже багатослівна відповідь на інше питання.
mustaccio

1
Ти мене жартуєш?
МістерМ

Чи можете ви пояснити, що не так чи що не можна застосувати до питання?
Містер М.

2
Гей, г-н. Мені справді подобається ваша відповідь. Чому? У моєму старому відповіді, я сказав в вселенні # 1: If you index like this, you can either look for the whole string or do left-oriented LIKE searches. Я також сказав в вселенні # 3: If you are looking for one specific value and those values could be lengths well beyond 32 characters, you could store the hash value:. Ваша відповідь адекватно демонструє, чому не слід використовувати величезні клавіші та слід індексувати на самих лівих символах, що може змінити продуктивність. Ваша відповідь належить тут. +1 для вашої відповіді та Ласкаво просимо до DBA StackExchange.
RolandoMySQLDBA
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.