В настоящее время я работаю с набором данных по сходству слов. Данные очень просты - у вас есть пары слов и значение сходства. (Собака, кошка, 43000)
Я перевел необработанные данные в таблицу MySQL со следующей структурой:
word1_id: INT(11), Primary Key, Not Null
word2_id: INT(11), Primary Key, Not Null
value: INT(11), Not Null
При создании таблицы я также определил индекс (в дополнение к индексу первичного ключа):
PRIMARY: BTREE, #1 word1_id, #2 word2_id
Word2: BTREE, #1 word2_id, #2 word1_id
Есть 50 000 уникальных слов. Данные полностью статичны - как только вы впервые импортируете его в таблицу, ничего не меняется. Примером данных является:
word1_id ; word2_id ; value
1 ; 2 ; 48971754
1 ; 3 ; 75997417
1 ; 4 ; 18285783
..
1 ; 50000 ; 127
2 ; 3 ; 1046254
2 ; 4 ; 268081
...
Цель проста: для данного целевого слова (int) найдите наиболее похожие слова.
Для этого таблица должна найти все записи, в которых целевой INT (например, 436) находится либо в столбце 1 (436; 543; 475652), либо в столбце 2 (72; 436; 934454) и возвращает отсортированный результат, на основе столбца 3.
Моя проблема заключается в следующем:
При поиске целевой INT в первом столбце процесс выполняется быстро (например, 0,1 секунды).
SELECT
value, word2_id
FROM
cooccurrence
WHERE
word1_id = (436)
ORDER BY value DESC;
Однако делать то же самое и для инструкции WHERE, основанной на столбце 2, занимает очень много времени (например, 1,5-10 секунд)
SELECT
value, word1_id
FROM
cooccurrence
WHERE
word2_id = (436)
ORDER BY value DESC;
Вопросы:
Почему гораздо медленнее делать WHERE на основе столбца 2, в отличие от столбца 1. Не следует ли индексировать таблицу "отсортированными" версиями данных на основе обоих столбцов?
Является ли эта структура таблицы хорошим способом решения этой проблемы? Есть ли какие-то очевидные оптимиза ции?
Конечная цель состоит в том, чтобы расстояние (колонка 3) было равно FLOAT и добавить четвертую колонку (INT), содержащую Год. Затем вы увидите, как меняется список большинства похожих слов с мишенью. Это означает, что данные (и таблица) будут резко увеличиваться - например, от нескольких гигабайт до сотен гигабайт. Это может существенно изменить ситуацию?
PRIMARY KEY(word1_id, word2_id),
INDEX(word2_id, value, word1_id),
INDEX(word1_id, value, word2_id)
Позвольте мне проанализировать
SELECT
value, word2_id
FROM
cooccurrence
WHERE
word1_id = (436)
ORDER BY value DESC;
Это происходит примерно так, используя INDEX(word2_id, value, word1_id)
:
word1_id = (436)
. (WHERE
)ORDER BY value DESC
)value, word2_id
, (SELECT
) Если у вас будет только 50K слов, перейдите из INT SIGNED
MEDIUMINT UNSIGNED
в MEDIUMINT UNSIGNED
. Это позволит сэкономить 6 байт в строке этой таблицы.
Как только вы добавили еще один столбец и изменили запрос, то, что я сказал, будет в основном неадекватным. Давайте посмотрим на SELECT
который включает year
.
При запросе запроса производительности EXPLAIN SELECT...
Таким образом, мы можем указать на это, чтобы сказать, какие ключи вы получаете.