我有一个非常简单的表,用于记录成员个人资料上的访问,具有多列密钥(member_id,visitor_id,month_visited)和更精确的日期。 month_visited是一个CHAR(7)列,如:'2013-10'
每个新月,我想在另一个表中压缩上个月的数据,然后将其删除。
我的要求很简单:
DELETE FROM visits WHERE month_visited = '2013-10'
需要AGES才能删除这些行,就像在我的专用服务器上几分钟一样。当我只查询一个简单的SELECT COUNT(*) FROM visits
时,情况也是如此。
我有2013-10的1.8M参赛作品。
但这需要很长时间。当我尝试
时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列上添加了一个IND :)(正如EXPLAIN所示,实际上,但它没有使用它......)如何改进那些(显然)简单查询?我是MySQL中的菜鸟,但我认为执行这些查询需要几分钟才是正常的。
感谢您的任何意见!
致以最诚挚的问候,
答案 0 :(得分:5)
我在这个答案中总结了我的评论。
通常,当没有使用索引时,这是因为使用索引不会有太大帮助。也就是说,与全表扫描相比,它不会节省太多时间(当索引的基数较低时,这往往会发生)。这似乎就是这种情况,因为表中的行数与要选择的行数大致相同。在这种情况下,完整扫描通常比使用索引便宜。
此外,删除是“写入”操作。索引优化读取,代价是使写入更加昂贵(因为写入时索引重建)。因此,您有一些复杂的指数这一事实无济于事,但会加剧问题。当索引缩小要检索的行数时,索引是有意义的;否则它不会带来任何实际收益,甚至可能会产生额外的开销。此外,在最好的情况下,索引可以使SELECT更有效。但它不会使写入(插入,更新和删除)更快地工作;相反,它会使它们表现更差。
所以,你应该试着摆脱不是绝对必要的指数。请记住,索引是一种权衡,可能会使读取操作(选择)更快,但代价是使写入操作(插入,更新,删除)变慢。这是因为索引必须在写入后重建。
您可能想尝试一下:“如果您要从表中删除许多行,使用DELETE QUICK后跟OPTIMIZE TABLE可能会更快。这会重建索引而不是执行许多索引块合并操作“。 dev.mysql.com/doc/refman/5.0/en/delete.html
另一种选择(可能有效或无效,只是在这里大声思考):如果你想从visitss中删除除了几行之外的所有行,也许你可以将“WHERE month!='2013-10'中的行插入一个辅助表,TRUNCATE访问,然后将aux表中的行插回访问,最后TRUNCATE aux表。但是,正如你所指出的那样,你需要在这个进程运行时进行某种锁定。
答案 1 :(得分:1)
只有在条件中使用第一个关键组件时,才能使用多列键。在您的情况下,这意味着只有在您的条件包含
时才会使用您的密钥(member_id, visitor_id, month_visited)
创建一个以month_visited
作为第一个组件的密钥。