2010-01-19 8 views
0

Предположим, что мне нужно запросить партнеров корпорации. У меня есть таблица «транзакции», которая содержит данные о каждой сделанной транзакции.Оптимизация запроса MySQL с большим предложением IN() или присоединением к производной таблице

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.

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

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

ответ

1

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

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; 
+0

Спасибо за ваше время, Фил. Первый запрос не может использовать индекс по той же причине, что и моя производная таблица. Второй использует правильные индексы, но не возвращает правильные данные. Я немного скорректировал его, и, хотя он использует индекс, он помечен как «использование временных» и «using filesort», и, по-видимому, по этой причине он занимает столько же времени, сколько запросы, которые не могут использовать индекс. Я думаю, что ты на что-то. –

+0

Жаль, что это не сработало. Это было именно то, что я хотел бы попробовать. Я нахожу, что для некоторых запросов MySQL просто не может сделать это быстро, поэтому вам нужно найти обходной путь. Проводка некоторых данных позволит другим играть с ней. –

0

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

Можете ли вы указать, что означают идентификаторы customerID, employeeID и corporationID? Как я знаю, что сотрудники A и B принадлежат корпорации 1 - в этом случае корпорация 1 является корпоративным, а корпорация 2 является клиентом и поэтому хранится в идентификаторе клиента?

Если это так, то вам просто нужно сделать группу путем: (. Или выбрать и группу по OrderId, если вы хотите одну строку в порядке, а не по одной строке на клиента)

SELECT customerID 
FROM transactions 
WHERE corporationID = 1 
GROUP BY customerID 

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

Наоборот, возвращает все корпорации, которые продаются в корпорации 2.

SELECT corporationID 
FROM transactions 
WHERE customerID = 2 
GROUP BY corporationID 
+0

Спасибо за Ваш ответ.Хотя вы верны, что запрос вернет корпорацию 1, она также вернет другие корпорации, которые были вовлечены в одни и те же транзакции (то есть, ассоциированные компании корпорации 1). Это данные, которые я ищу. –

+0

Вот описание поля, которое вы запросили. Я прошу прощения за стену текста - кажется, нет возможности создавать разрывы строк в комментариях к переполнению стека. «transactionID» - это уникальный идентификатор транзакции. Это неважно для этого запроса. 'orderID' - это идентификатор заказа, связанного с транзакцией. «customerID» - это идентификатор лица, которому был доставлен заказ. «employeeID» - это идентификатор сотрудника, участвующего в транзакции. «corporationID» - это идентификатор корпорации, в которой работал сотрудник в то время. –