2013-11-01 61 views
1

我有一个非常简单的表,用于在成员配置文件上记录访问,具有多列键(member_id,visitor_id,month_visited)和更精确的日期。 month_visited是一个类似CHAR(7)的列:'2013-10'Mysql没有在哪里使用索引

每个新月,我想在另一个表中压缩上个月的数据,然后删除它。

我的要求很简单:

DELETE FROM visits WHERE month_visited = '2013-10' 

它需要年龄删除这些行,就像我的专用服务器上几分钟。当我查询简单的SELECT COUNT(*) FROM visits时也是如此。

我有2013-10的180万条目。

但它需要时间。当我尝试

EXPLAIN SELECT * FROM visits WHERE month_visited = "2013-10" 

它告诉我:

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE visits ref idx_month_visited idx_month_visited 21 const 1782148 Using where 

“使用,其中”,严重?

编辑:对不起,我忘了指定,我还增加了指数只是month_visited列:)(如EXPLAIN显示,实际上,但它不使用它...)

我怎么能改善这些(显然)简单的查询?我是MySQL的noob,但我不认为这是很正常的,它需要几分钟时间来执行这些查询。

感谢您的任何意见!如果第一关键部件均在条件中使用

此致

+0

这张表有多少行? –

+0

我在问,因为在我有限的体验中,当没有使用索引时,它通常是因为使用它并没有什么帮助;也就是说,与全表扫描相比,它不会节省太多时间(当索引的基数很低时,这往往会发生) –

+0

另外,删除是一个“写”操作。索引优化读操作,代价是写操作更加昂贵(因为写操作时索引重建)。所以,你有一些复杂的指数这一事实并没有帮助,但会加重问题。 –

回答

3

我在这个答案中总结我的意见。

一般来说,当一个索引没有被使用时,这是因为使用它没有多大帮助。也就是说,与全表扫描相比,这不会节省太多时间(当索引的基数较低时,这往往会发生)。这似乎就是这种情况,因为表中的行数与您要选择的行数相同。在这种情况下,全面扫描通常比使用索引便宜。

另外,删除是一个“写”操作。索引优化读操作,代价是写操作更加昂贵(因为写操作时索引重建)。所以,你有一些复杂的指数这一事实并没有帮助,但会加重问题。索引在缩小要检索的行数时有意义;否则它不会带来真正的收益,甚至会带来额外的开销。另外,在最好的情况下,索引可以使SELECT更高效。但它不会使写入(插入,更新和删除)工作更快;相反,它会使它们表现更差。

所以,你应该尽量摆脱不是绝对必要的指标。记住一个索引是一种折衷,这可能会使读取操作(选择)更快,但会使写入操作(插入,更新,删除)变慢。这是因为索引必须在写入后重新编译。

您可能会想尝试一下:“如果要从表中删除多行,使用DELETE QUICK和OPTIMIZE TABLE可能会更快,这会重建索引而不是执行多个索引块合并操作“。 dev.mysql.com/doc/refman/5.0/en/delete.html

还有另外一个选择(可能工作与否,只是在这里大声思考):如果你想从visitss中删除几行,也许你可以将行“WHERE month!='2013-10'插入到辅助表中,TRUNCATE访问,然后将辅助表中的行插入到访问中,最后截断aux表。然而,正如你指出的那样,你在这个过程正在运行的时候需要提供某种锁定

1

多列密钥只能被使用。在你的情况,这意味着你的钥匙(member_id, visitor_id, month_visited)将只用于如果你的条件包括

  • member_id或
  • member_id和visitor_id
  • member_id和visitor_id和month_visited。

创建一个具有month_visited作为第一个组件的密钥。

+0

对不起,我忘了指定我还在month_visited上添加了一个INDEX,就像它在EXPLAIN中显示的那样,但是,Mysql似乎并不愿意使用它! –

+0

仅供参考:我已经启动了我的PHP脚本(执行数据压缩,以及为json备份选择行,以及删除行),并且它已运行超过30分钟,现在仍然不行完了。 –