2011-12-23 95 views
3

我有两个表 - 一个叫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 

这是伟大的 - 它列出了每个客户ID和他们的最后一个动作。但查询是极端缓慢的场合(注:在customer_records有近2万条记录)。任何人都可以提供关于如何将查询的这个怪物排序或调整我的表以提供更快结果的任何提示?我正在使用MySQL。任何帮助真的很感激,谢谢。

编辑:为了清楚起见,我需要查看上次操作是“无论”的客户列表。

+0

这是否意味着如果客户的最后一个动作(由ActionDate)是*不是*'无论'那么该客户不应该被列出?对于列出的客户,您是否只想要客户,或者他们最后的行动,还是他们所有的行为? – MatBailie 2011-12-23 00:31:13

+0

@Dems如果客户的最新'ActionType'不是'任何',那么他们不应该被显示。对于那些拥有最新'ActionType'的'无论'我都需要'customer_records'的信息 - 但这并不需要在一个查询中全部覆盖。 – Jonathon 2011-12-23 00:41:28

回答

5

由他们的最后一个动作筛选客户,你可以使用相关子查询...

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

谢谢 - 第一个查询返回了预期的结果(太棒了!),但花了* 445秒*来完成: - | !第二个查询返回一个空集。 – Jonathon 2011-12-23 15:24:29

+0

@JonnyKeogh - 在那里有两个拼写错误,现在已更正。 * [您是否在customer_actions(CustomerID,ActionDate)上有覆盖索引?] * – MatBailie 2011-12-23 15:40:49

+0

工作,非常感谢! – Jonathon 2011-12-23 17:17:44

2

我不确定我是否了解这些要求,但它在我看来像一个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的记录不应该造成性能问题

+0

除了上述如果你正在重新考虑这一点,那么我强烈建议你离开*并仅使用直接需要的列名(选择*是一个很大的性能点击) – Codingo 2011-12-23 00:29:02

+0

@Codingo - 你是正确的离场。该查询已修复。 – 2011-12-23 00:30:56

+0

这个查询选择所有在某个时间点对他们的记录进行过“任何”操作的客户,但我需要查看客户上次执行的操作对他们的记录是“什么”。对不起,我原来的帖子不太清楚。 – Jonathon 2011-12-23 14:43:49

2

请注意,我已经适应利芬的答案(我做了一个单独的职位,因为这是一个评论太长)。解决方案本身的任何功劳都归功于他,我只是试图向您展示一些提升性能的关键点。

如果速度是一个问题,然后下面应该给你提高它的一些建议:

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 

的几个注意事项:

  • 在某些情况下,我发现左外连接要快,然后内部连接 ​​- 对于这个查询,两者都值得衡量性能
  • 避免返回*尽可能避免返回*
  • 您不必引用'c河x',但是当你开始处理可能有多个连接的大型查询时,这是一个很好的习惯(一旦你开始这样做,这会很有意义的)
  • 当总是使用连接加入主键上
+0

'TOP 100'应该通过'Limit 100',但我猜想OP可以解决这个问题:)但是,对于* always *加入主键?我在这里并不同意。如果“动作”表具有代理主键,则OP所需的功能仍需要加入不在主键中的字段。我想说的是,当MySQL使主键成为聚集索引时,这样做有实际的好处,但是如果你的逻辑意味着你不能,那么确保你有一个合适的索引。 – MatBailie 2011-12-23 01:42:15

+0

非常有效的一点 - 现在将更多地考虑到这一点。非常感谢你。 – Codingo 2011-12-23 01:47:11

1

也许我错过了一些东西,但是简单的连接和where子句有什么问题?

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

OP需要一个客户列表,他们在Action表中的最后一个条目是特定的操作。 “他们在动作表中的最后一个条目”是这里缺少的部分。 * [但我确实必须检查一下评论才能确定。] * – MatBailie 2011-12-23 01:29:38

+0

啊,是的,我重读了OP。 “我希望能够做的是显示来自customer_records的最后一个ActionType是特定值的记录列表。”这意味着我的回应:我错过了后来的“它列出了每个客户ID和他们的最后一次行动” – xQbert 2011-12-23 10:21:25