两表加入指数优化

时间:2013-02-06 20:01:34

标签: mysql optimization

我有以下表格:

items (item_id (PRIMARY), item_name)
activity (activity_id (PRIMARY), item_id (INT), user_id (INT), lat (FLOAT), lng (FLOAT), created_at)

我想做以下查询:

SELECT
  i.item_id,
  i.item_name,
  count(distint a.user_id) as total_count
FROM activity as a
  INNER JOIN item as i
    on a.item_id = i.item_id
WHERE (a.lat BETWEEN XXXXXXX
       and XXXXXXX
       and a.lng BETWEEN XXXXXXX
       and XXXXXXX)
    and created_at >= DATE_SUB(NOW(), INTERVAL 5 DAY)
GROUP by a.bid
ORDER BY RAND()
LIMIT 5

这是对3-5百万记录表的严重查询,即使我有活动索引:

item_index (item_id, lat, lng, created_at)

这不会在EXPLAIN中使用,它只是默认为“item_id”。我想我要问的是 - 需要添加哪些索引才能使这个查询快速运行,或者我可以进行优化?

2 个答案:

答案 0 :(得分:0)

尝试像这样的派生子查询

SELECT
  i.item_id,
  i.item_name,
  count(distint a.user_id) as total_count
FROM activity as a
  INNER JOIN (select
        item_id,
        item_name
          from item
          where a.lat BETWEEN XXXXXXX
          and XXXXXXX
          and a.lng BETWEEN XXXXXXX
          and XXXXXXX) as i
    on a.item_id = i.item_id
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 5 DAY)
GROUP by a.bid
ORDER BY RAND()
LIMIT 5

答案 1 :(得分:0)

该索引可用于where子句,on子句或两者。

where子句中,A,B和C列的索引(按此顺序)可用于以下情况:

  • A上的平等(A = a
  • 对A进行有序比较(例如A < aA > a
  • A和B上的平等(例如A = a and B = b
  • A上的平等,B上的有序比较(例如A = a and B < b
  • A,B和C上的平等
  • A和B上的平等以及C
  • 的有序比较

您的where子句具有相等性,然后是两次有序比较。我建议将a.lngbetween更改为in,并将索引更改为item_index (item_id, lng, lat, created_at)

您还应该删除item_index(item_id)上的索引,因为它不需要。这个新索引可以在任何地方使用。

由于order by rand(),此查询必须在返回任何行之前生成整个结果集。真正提高性能的唯一方法是希望where条件具有高度选择性,因此它们会减小生成集的大小。

如果您可以构建查询以从activityitem获取5行然后执行连接,那么您可能会感觉更好。