Эффективность запроса (множественный выбор) - PullRequest
3 голосов
/ 23 декабря 2011

У меня есть две таблицы - одна называется customer_records, а другая - customer_actions.

customer_records имеет следующую схему:

CustomerID (auto increment, primary key)
CustomerName
...etc...

customer_actions имеет следующую схему:

ActionID (auto increment, primary key)
CustomerID (relates to customer_records)
ActionType
ActionTime (UNIX time stamp that the entry was made)
Note (TEXT type)

Каждый раз, когда пользователь выполняет действие с записью клиента, в customer_actions вводится запись, и пользователю предоставляется возможность ввести заметку. ActionType может быть одним из нескольких значений (например, «Обязательное обновление» или «Дополнительная информация о регистре» - может быть только одним из списка параметров).

Что я хочу сделать, это отобразить список записей из customer_records, где последний ActionType имел определенное значение.

Пока что я искал в сети / SO и нашел этого монстра:

SELECT * FROM (
    SELECT * FROM (
        SELECT * FROM `customer_actions` ORDER BY `EntryID` DESC
    ) list1 GROUP BY `CustomerID`
) list2 WHERE `ActionType`='whatever' LIMIT 0,30

Что здорово - в нем перечислены все идентификаторы клиентов и их последние действия. Но в некоторых случаях запрос чрезвычайно медленный (примечание: в customer_records есть около 20 000 записей). Может кто-нибудь предложить какие-либо советы о том, как я могу отсортировать этого монстра запроса или настроить свою таблицу, чтобы дать более быстрые результаты? Я использую MySQL. Спасибо за любую помощь, спасибо.

Редактировать: Чтобы было ясно, мне нужно увидеть список клиентов, у которых последнее действие было «что угодно».

Ответы [ 4 ]

5 голосов
/ 23 декабря 2011

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

SELECT
  *
FROM
  customer_records
INNER JOIN
  customer_actions
    ON  customer_actions.CustomerID = customer_records.CustomerID
    AND customer_actions.ActionDate = (
           SELECT
             MAX(ActionDate)
           FROM
             customer_actions  AS lookup
           WHERE
             CustomerID = customer_records.CustomerID
        )
WHERE
  customer_actions.ActionType = 'Whatever'

Может оказаться более эффективным избегать коррелированного подзапроса следующим образом ...

SELECT
  *
FROM
  customer_records
INNER JOIN
  (SELECT CustomerID, MAX(ActionDate) AS ActionDate FROM customer_actions GROUP BY CustomerID) AS last_action
    ON customer_records.CustomerID = last_action.CustomerID
INNER JOIN
  customer_actions 
    ON  customer_actions.CustomerID = last_action.CustomerID
    AND customer_actions.ActionDate = last_action.ActionDate
WHERE
  customer_actions.ActionType = 'Whatever'
2 голосов
/ 23 декабря 2011

Обратите внимание, что я адаптировал ответ Ливена (я сделал отдельный пост, так как это было слишком длинно для комментария).Любая заслуга в этом решении достается ему, я просто пытаюсь показать вам некоторые ключевые моменты для повышения производительности.

Если скорость вызывает беспокойство, то следующие рекомендации должны дать вам несколько советов по ее улучшению:

select top 100 -- Change as required
        cr.CustomerID ,
        cr.CustomerName,
        cr.MoreDetail1,
        cr.Etc
from    customer_records cr
        inner join customer_actions ca 
            on ca.CustomerID = cr.CustomerID
where   ca.ActionType = 'x'
order by cr.CustomerID

Несколько замечаний:

  • В некоторых случаях я считаю, что левые внешние соединения быстрее, чем внутренние соединения - для этого запроса стоило бы измерить производительность для обоих запросов
  • Избегайте возврата * везде, где это возможно
  • Вам не нужно ссылаться на 'cr.x' при первоначальном выборе, но это хорошая привычка, когда вы начинаете работать над большими запросами, которые могут иметь несколько объединенийв них (это будет иметь большой смысл, как только вы начнете делать это
  • При использовании объединений всегда объединение по первичному ключу
2 голосов
/ 23 декабря 2011

Я не уверен, что понимаю требования, но мне кажется, что для этого достаточно JOIN.

SELECT  cr.CustomerID, cr.CustomerName, ...
FROM    customer_records cr
        INNER JOIN customer_actions ca ON ca.CustomerID = cr.CustomerID
WHERE   `ActionType` = 'whatever'
ORDER BY
        ca.EntryID

Обратите внимание, что 20 000 записей не должны создавать проблемы с производительностью1005 *

1 голос
/ 23 декабря 2011

Может быть, я что-то упускаю, но что не так с простым соединением и предложением where?

Select ActionType, ActionTime, Note
FROM Customer_Records CR
INNER JOIN customer_Actions CA 
  ON CR.CustomerID = CA.CustomerID
Where ActionType = 'added case info'
...