Оптимизация запроса MySQL с помощью большого предложения IN() или объединения производной таблицы

StackOverflow https://stackoverflow.com/questions/2091777

Вопрос

Допустим, мне нужно опросить сотрудников корпорации.У меня есть таблица «Транзакции», которая содержит данные о каждой совершенной транзакции.

CREATE TABLE `transactions` (
  `transactionID` int(11) unsigned NOT NULL,
  `orderID` int(11) unsigned NOT NULL,
  `customerID` int(11) unsigned NOT NULL,
  `employeeID` int(11) unsigned NOT NULL, 
  `corporationID` int(11) unsigned NOT NULL,
  PRIMARY KEY (`transactionID`),
  KEY `orderID` (`orderID`),
  KEY `customerID` (`customerID`),
  KEY `employeeID` (`employeeID`),
  KEY `corporationID` (`corporationID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Запросить ассоциированные объекты в этой таблице довольно просто, но есть одна особенность:Запись о транзакции регистрируется один раз для каждого сотрудника, поэтому в одном заказе может быть несколько записей для одной корпорации.

Например, если бы сотрудники A и B из корпорации 1 оба участвовали в продаже пылесоса корпорации 2, в таблице «транзакции» было бы две записи;по одному на каждого сотрудника и оба для корпорации 1.Однако это не должно повлиять на результаты.Сделку корпорации 1, независимо от того, сколько ее сотрудников было в ней задействовано, следует рассматривать как единую.

Легко, подумал я.Я просто сделаю соединение производной таблицы, например:

SELECT corporationID FROM transactions JOIN (SELECT DISTINCT orderID FROM transactions WHERE corporationID = 1) AS foo USING (orderID)

Запрос возвращает список корпораций, которые участвовали в сделках с корпорацией 1.Это именно то, что мне нужно, но это очень медленно, поскольку MySQL не может использовать индекс CorporationID для определения производной таблицы.Я понимаю, что это относится ко всем подзапросам/производным таблицам в MySQL.

Я также пытался запросить коллекцию идентификаторов заказов отдельно и использовать смехотворно большое предложение IN() (обычно более 100 000 идентификаторов), но, как оказалось, у MySQL есть проблемы с использованием индексов в смехотворно больших предложениях IN(), а также в результате время запроса не улучшается.

Есть ли другие варианты или я исчерпал их оба?

Это было полезно?

Решение

Если я понимаю ваше требование, вы можете попробовать это.

select distinct t1.corporationID
from transactions t1
where exists (
    select 1
    from transactions t2
    where t2.corporationID =  1
    and t2.orderID = t1.orderID)
and t1.corporationID != 1;

или это:

select distinct t1.corporationID
from transactions t1
join transactions t2
on t2.orderID = t1.orderID
and t1.transactionID != t2.transactionID
where t2.corporationID = 1
and t1.corporationID != 1;

Другие советы

Ваши данные не имеют для меня никакого смысла, я думаю, что вы используете CorporationID, где вы имеете в виду идентификатор клиента в какой-то момент, поскольку ваш запрос соединяет таблицу транзакций с таблицей транзакций для CorporationID = 1 на основе orderID, чтобы получить идентификаторы корпорации... что тогда будет 1, верно?

Не могли бы вы уточнить, что означают идентификаторы клиента, идентификатора сотрудника и идентификаторы корпорации?Как я узнаю, что сотрудники A и B принадлежат корпорации 1? В этом случае корпорация 1 является идентификатором корпорации, а корпорация 2 является клиентом и хранится в идентификаторе клиента?

Если это так, вам просто нужно создать группу:

SELECT customerID
FROM transactions
WHERE corporationID = 1
GROUP BY customerID

(Или выберите и сгруппируйте по идентификатору заказа, если вам нужна одна строка для каждого заказа вместо одной строки для каждого клиента.)

Используя группу by, вы игнорируете тот факт, что существует несколько повторяющихся записей, за исключением идентификатора сотрудника.

И наоборот, чтобы вернуть все корпорации, которые продали корпорации 2.

SELECT corporationID
FROM transactions
WHERE customerID = 2
GROUP BY corporationID
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top