Производительность MySQL в операторе ИЛИ

#mysql #wordpress #indexing #entity-attribute-value

Вопрос:

Это мой столик:

 CREATE TABLE `e_relationship` (
`OID` int(11) NOT NULL AUTO_INCREMENT,
`E_E_OID` int(11) NOT NULL,
`E_E_OID2` int(11) NOT NULL,
`REL_DISPLAY` text NOT NULL,
`APP_OID` int(11) NOT NULL,
`META_OID` int(11) NOT NULL,
`STORE_DATE` datetime NOT NULL,
`UID` int(11) DEFAULT NULL,
PRIMARY KEY (`OID`),
KEY `Left_Entity` (`E_E_OID`),
KEY `Right_Entity` (`E_E_OID2`),
KEY `Meta_Left` (`META_OID`,`E_E_OID`),
KEY `Meta_Right` (`META_OID`,`E_E_OID2`)
) ENGINE=InnoDB AUTO_INCREMENT=310169 DEFAULT CHARSET=utf8;
 

Следующий запрос занимает около 2,5-3 мс, результирующий набор составляет 1290 строк, а общее количество строк в таблице составляет 1 008 700.:

 SELECT * FROM e_relationship WHERE e_e_oid=@value1 OR e_e_oid2=@value1
 

Это результат EXPLAIN :

 id: 1
select_type: SIMPLE
table: e_relationship
type: index_merge
possible_keys: Left_Entity,Right_Entity
key: Left_Entity,Right_Entity
key_len: 4,4
ref: NULL
rows: 1290
Extra: Using union(Left_Entity,Right_Entity); Using where
 

Я хотел бы ускорить этот запрос, так как это очень важно в моей системе, я не уверен, что достиг какого-то узкого места в mysql, так как количество записей уже перевалило за миллион, и хотел бы знать о других возможных стратегиях для повышения производительности.

Комментарии:

1. 2,5-3 мс кажется более чем разумным, учитывая количество строк и распределение данных.

2. вы можете попробовать В операторе.

3. Во-первых (и, как заявил Михай), 3 мс-довольно хорошее время отклика для таблицы записей объемом 1 млн. Во-вторых, попробуйте отслеживать СИСТЕМУ (процессор, ПАМЯТЬ, ДИСК) и посмотреть, достигает ли какой-либо из них высокого процента.

4. Согласно объяснению, MySQL уже использует оптимизацию слияния индексов для вашего запроса, это так быстро, как вы можете сделать без использования явного объединения. Вы сказали в комментарии к удаленному ответу, что объединение происходило медленнее. Это все, что вы можете получить как разработчик. С этого момента передайте задачу администратору базы данных, который может настроить параметры MySQL для повышения производительности запроса. Тем не менее, я склонен согласиться с мнением, что 2-3 мс кажутся достаточно быстрой производительностью.

5. Ваш запрос и так оптимизирован, и 3 мс-хороший результат. Если вам не нужны все столбцы и добавить индекс покрытия, вы можете сохранить таблицу поиска (чтобы испытать его, попробуйте select id from вместо select * from ), но в остальном, это зависит от внешних факторов: как вы называете ваш запрос (например, использовать подготовленные операторы в PHP), сколько/какие другие запросы, и вашу общую производительность базы данных (так что в основном: сервер цене). Оценка: Для 1 м строк (если text столбец не слишком велик) ваш запрос, выполняемый непосредственно в MySQL на простаивающем (наполовину недавнем) процессоре с достаточным объемом оперативной памяти, не должен показывать ничего, кроме 0,000 сек.

Ответ №1:

Иногда у MySQL возникают проблемы с оптимизацией OR запросов. В этом случае вы можете разделить его на два запроса, используя UNION :

 SELECT * FROM relationship WHERE e_e_oid = @value1
UNION
SELECT * FROM relationship WHERE e_e_oid2 = @value2
 

Каждый подзапрос будет использовать соответствующий индекс, а затем результаты будут объединены.

Однако в простых случаях MySQL может автоматически выполнить это преобразование, и он делает это в вашем запросе. Вот что Using union EXPLAIN означает вывод.

Комментарии:

1. Это занимает еще больше времени

Ответ №2:

Есть столик E_E_OIDs . В нем будет (до) 2 строки на каждую e_relationship . Затем

 SELECT ...
    FROM eeoids AS ee
    JOIN e_relationship AS er ON er.ooid = ee.oid
 

И измените с 2 столбцов на один. И избавьтесь от 2 индексов.

Оказывает ли эффект ИЛИ даже быстрее, чем UNION .

(Остальные подробности оставлены читателю.)

Аналогия

Предположим, у человека есть несколько телефонных номеров (стационарный, мобильный, рабочий и т. Д.), И я хочу просмотреть его запись на основе одного телефонного номера. Итак, я строю таблицу phone : personID пар и индексирую ее phone . Тогда я делаю

 SELECT ...
    FROM Phones AS nums
    JOIN Persons AS x ON x.personID = nums.personID
    WHERE nums.phone = '123-555-1212'
 

Примечание: В таблице нет номера телефона Persons .

Твое E_E_OID похоже на мое phone .

Комментарии:

1. Не будет ли объединение контрпродуктивным?

2. JOIN вероятно , будет меньше накладных расходов, чем OR или UNION или index merge .

3. Но JOIN это не замена, а дополнение, конечно, мне все еще нужно OR и index merge на E_E_OIDs столе

4. Вы ищете один OID? Или два?

5. Мне нужно отфильтровать E_E_OID и E_E_OID2