Вот несколько вещей, которые я бы попробовал в порядке возрастания сложности:
(проще) - Убедитесь, что у вас есть правильный индекс покрытия
CREATE INDEX ix_temp ON relations (relation_title, object_title);
Это должно максимизировать производительность при существующей схеме, поскольку (если ваша версия оптимизатора mySQL действительно глупа!), Это минимизирует количество операций ввода-вывода, необходимых для удовлетворения вашего запроса (в отличие от того, если индекс находится в обратном порядке, где весь индекс должен быть отсканирован), и он покроет запрос, так что вам не придется прикасаться к кластерному индексу.
(немного сложнее) - убедитесь, что ваши поля varchar настолько малы, насколько это возможно
Одна из проблем, связанных с индексами varchar в MySQL, заключается в том, что при обработке запроса полный объявленный размер поля помещается в ОЗУ. Таким образом, если у вас есть varchar (256), но вы используете только 4 символа, вы все равно платите 256-байтовое использование оперативной памяти во время обработки запроса. Ой! Так что, если вы можете легко сократить свои пределы varchar, это должно ускорить ваши запросы.
(тяжелее) - нормализовать
30% ваших строк, имеющих одно строковое значение, - это чистый крик для нормализации в другую таблицу, чтобы вы не дублировали строки миллионы раз. Рассмотрите возможность нормализации в три таблицы и использования целочисленных идентификаторов для их объединения.
В некоторых случаях вы можете нормализовать под прикрытиями и скрыть нормализацию с представлениями, которые соответствуют имени текущей таблицы ... тогда вам нужно только сделать так, чтобы ваши запросы INSERT / UPDATE / DELETE знали о нормализации, но могут оставить ваш выбор один.
(самое сложное) - хэшируйте ваши строковые столбцы и индексируйте хэши
Если нормализация означает изменение слишком большого количества кода, но вы можете немного изменить свою схему, вы можете рассмотреть возможность создания 128-битных хэшей для ваших строковых столбцов (используя функцию MD5 ). В этом случае (в отличие от нормализации) вам не нужно изменять все ваши запросы, только INSERT и некоторые из SELECT. В любом случае вы захотите хэшировать свои строковые поля, а затем создать индекс для хешей, например,
CREATE INDEX ix_temp ON relations (relation_title_hash, object_title_hash);
Обратите внимание, что вам нужно поэкспериментировать с SELECT, чтобы убедиться, что вы выполняете вычисления с помощью хеш-индекса, а не извлекаете кластеризованный индекс (необходим для разрешения фактического текстового значения object_title, чтобы удовлетворить запрос ).
Кроме того, если отношение_титла имеет небольшой размер varchar, но заголовок объекта имеет большой размер, то вы можете потенциально хэшировать только объект_титл и создать индекс для (relation_title, object_title_hash)
.
Обратите внимание, что это решение помогает, только если одно или оба из этих полей очень длинные относительно размера хэшей.
Также обратите внимание, что при хешировании есть интересные влияния на чувствительность к регистру / сопоставлению, поскольку хеш строчной строки не совпадает с хешем заглавной. Поэтому вам необходимо убедиться, что вы применяете канонизацию к строкам перед их хэшированием - другими словами, используйте только хеш-регистр, если вы находитесь в БД без учета регистра. Вы также можете обрезать пробелы с начала или до конца, в зависимости от того, как ваша БД обрабатывает начальные / конечные пробелы.