Индекс MySQL для столбца TEXT не эффективен
У меня есть довольно простая таблица для хранения пар ключ: значение, настроенная так:
CREATE TABLE `assetProperties` (
`propertyKey` varchar(255) NOT NULL,
`propertyValue` text NOT NULL,
`id` bigint(20) NOT NULL,
`assetInstance_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK67F768435C68E1C0` (`id`),
KEY `FK67F76843FBDFC83F` (`assetInstance_id`),
KEY `keyIndex` (`propertyKey`),
KEY `valIndex` (`propertyValue`(255)),
CONSTRAINT `FK67F76843FBDFC83F` FOREIGN KEY (`assetInstance_id`) REFERENCES `assets` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
... и в этой таблице есть разумное количество записей:
mysql> select count(*) from assetProperties;
+----------+
| count(*) |
+----------+
| 19931305 |
+----------+
... и что я хочу сделать, это найти записи, которые точно соответствуют данной паре ключ: значение. Например, используя запрос как:
SELECT count(*) FROM assetProperties WHERE propertyKey = "Wood Species"
AND propertyValue = "Jarrah";
Без каких-либо индексов на propertyKey
а также propertyValue
этот запрос выполняется довольно медленно, примерно на 10+ секунд. Что и следовало ожидать. Проблема в том, что даже после добавления индексов в оба поля время запроса не улучшается.
Странно то, что индекс на propertyKey
кажется, работает правильно:
-- Before adding index
mysql> SELECT count(*) FROM assetProperties WHERE propertyKey = "Wood Species";
+----------+
| count(*) |
+----------+
| 339395 |
+----------+
1 row in set (9.37 sec) <-- bad
-- After adding index
mysql> SELECT count(*) FROM assetProperties WHERE propertyKey = "Wood Species";
+----------+
| count(*) |
+----------+
| 339395 |
+----------+
1 row in set (0.16 sec) <-- reasonable
... пока индекс на propertyValue
похоже, мало что изменило:
-- Before adding index
mysql> SELECT count(*) FROM assetProperties WHERE propertyValue = "Jarrah";
+----------+
| count(*) |
+----------+
| 219099 |
+----------+
1 row in set (12.51 sec) <-- bad
-- After adding index
mysql> SELECT count(*) FROM assetProperties WHERE propertyValue = "Jarrah";
+----------+
| count(*) |
+----------+
| 219099 |
+----------+
1 row in set (9.75 sec) <-- still garbage
Единственная разница между propertyKey
а также propertyValue
является то, что бывший varchar(255)
столбец и последний text
, Есть ли что-то, что мешает MySQL эффективно использовать индекс на text
колонка, или что я могу сделать, чтобы сделать запрос быстрее?
редактировать
Также попытался добавить многостолбцовый индекс по обоим полям. Не сделал разницы
И далее, если я добавлю новый столбец (скажем, propertyValueShort
) типа varchar(255)
и скопировать значения из propertyValue
в новый столбец и установить соответствующие индексы, он работает следующим образом:
mysql> SELECT count(*) FROM assetProperties WHERE propertyKey = "Wood Species" AND propertyValueShort = "Jarrah";
+----------+
| count(*) |
+----------+
| 219099 |
+----------+
1 row in set (0.14 sec) <-- acceptable
Так что это может быть немедленным ответом (самый длинный propertyValue
в настоящее время используется 88 символов, поэтому мне не нужно использовать text
там). Однако до сих пор не объясняет, почему индекс на text
колонка так плохо работает.
1 ответ
PRIMARY KEY (`id`),
KEY `keyIndex` (`propertyKey`),
->
PRIMARY KEY(property_key, id),
INDEX(id),
Зачем?
- InnoDB "кластеризует" ПК с данными. Это означает, что все строки с одинаковыми
property_key
теперь будет "рядом друг с другом", тем самым сводя к минимуму чтение с диска. - Является
id
AUTO_INCREMENT
? Если так,INDEX(id)
достаточно; ПК не нужен. Остальное... зачемid
? Вы можете избавиться от этого? На самом деле, нет; вам все равно нужно сделать ПК уникальным как-то.
Что ROW_FORMAT
стола? Как долго property_value
обычно? Они влияют на то, хранятся ли "большие" поля, такие как TEXT, рядом со строкой или хранятся отдельно.
(Итог: схемы ключ-значение - отстой.)