2012-01-03 1 views
2

Мне нужна помощь при следующем объединении. У меня есть один стол (около 20 миллионов рядов), который состоит из:Соедините таблицу с собой - производительность

MemberId (Primary Key) | Идентификатор (первичный ключ) | TransactionDate | Баланс

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

SELECT * 
FROM money 
WHERE money.Id = (SELECT MAX(Id) 
        FROM money AS m 
        WHERE m.MemberId = money.MemberId) 

Есть ли другие (более быстрые/умные) варианты?

+0

Конечно, первичный ключ является составным, а первый столбец - MemberId? – Benoit

+0

Umbrella имеет хороший ответ, но мне было бы очень интересно узнать, как MySQL работает с оператором 'IN' (замените первый' = '), если вы не возражаете. –

+0

@Benoit Да, первичный ключ является составным, а первый столбец - MemberId (это таблица MyIsam). – PKK

ответ

5

Во всех оптимизационных учебники и видеоролики, которые я пережил через, присоединяется всегда предпочитать подзапросов. При использовании подзапроса выполняется подзапрос для каждого сравнения, где, как и при объединении, выполняется только один раз.

SELECT * 
FROM money m 
INNER JOIN (
    SELECT memberId, MAX(id) AS maxid 
    FROM money 
    GROUP BY memberId 
) mmax ON mmax.maxid = m.id AND mmax.memberId = m.memberId 
+0

Действительно приятное решение. Это было намного быстрее, чем запрос, который я использовал – PKK

0

Другой вариант для поиска значений NULL в соединения слева:

SELECT m1.* 
    FROM money m1 
    LEFT JOIN money m2 ON m2.memberId = m1.memberId AND m2.id > m1.id 
WHERE m2.memberId IS NULL 

Но конечно Umbrella's answer лучше.

2

JOINing - это не лучший способ решить эту проблему. Рассмотрите возможность использования предложения GROUP BY, чтобы отсеять последнюю транзакцию для каждого члена, как это:

ВЫБРАТЬ MemberId, MAX (Id), TransactionDate, баланс от денег GROUP BY MemberId

UPDATE

как указано PKK, баланс будет выбран случайным образом. Похоже, вам все равно придется выполнить какое-то соединение. Рассмотрим этот вариант:

SELECT MemberId, Id, TransactionDate, Balance FROM money WHERE Id IN (
    SELECT MAX(Id) FROM money GROUP BY MemberId 
) 
+0

Конечно ... как я мог не думать об этом ... – Benoit

+0

Отредактировано для получения Max Id вместо даты – Umbrella

+0

TransactionDate и Balance будут выбраны случайным образом. Не соответствует MAX (Id) – PKK