2011-12-01 60 views
1

我试图找到我的users表副本(不要问,它的很多繁琐的),但我在创造我所创建的查询索引的问题。该表看起来像:查找重复行的索引?

+----------------+---------+------+-----+---------+----------------+ 
| Field   | Type | Null | Key | Default | Extra   | 
+----------------+---------+------+-----+---------+----------------+ 
| id    | int(10) | NO | PRI | NULL | auto_increment | 
| email   | text | YES | MUL | NULL |    | 
| username  | text | YES | MUL | NULL |    | 
| password  | text | YES |  | NULL |    | 
+----------------+---------+------+-----+---------+----------------+ 

还有其他领域,但这些是我正在寻找的。我写了寻找重复的查询是这样的:

SELECT COUNT(username) count,GROUP_CONCAT(id) ids,username,email,password 
    FROM users 
    GROUP BY username,email,password 
    HAVING COUNT(username) > 1 

我创建的索引是:

CREATE INDEX users_id_username_password_email 
    ON users id,username(64),password(64),email(64)); 

不幸的是,形容似乎并不使用这个指数:

mysql> describe SELECT COUNT(username) count,GROUP_CONCAT(id) ids, 
    -> username,email,password 
    -> FROM users 
    -> GROUP BY username,email,password 
    -> HAVING COUNT(username) > 1\G 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: users 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 705418 
     Extra: Using filesort 

所以根本的问题是,我应该创建找桌子上的重复条目,如本什么样的指标?

编辑:更改查询以匹配指数什么也没做:

mysql> describe SELECT COUNT(username) count,GROUP_CONCAT(id) ids, 
    -> username,password,email 
    -> FROM users 
    -> GROUP BY username,password,email 
    -> HAVING COUNT(username) > 1\G 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: users 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 705418 
     Extra: Using filesort 
+0

如果您正在寻找重复的,那么应该不是查询的最后一点是:'HAVING COUNT(用户名)> 1'呢?至于索引,它可能无所谓,因为像这样的查询,没有WHERE子句,最终必须扫描整个表。 –

+0

尝试交换'password'和'email'的顺序以匹配您的查询。 –

+0

呀,你抓住我的错字,我才。这是正确的代码,而不是在帖子中。 –

回答

2

没有意义的RDBMS,如果它需要反正读取每一行使用索引。索引不要紧的存在,列的索引的顺序并不重要,如果你使用FORCE INDEX它甚至不会没关系。

依此类推,如果我问你找到每一个字的出现“的”一书中,你可以使用索引在书的后面,或将你刚才读它从头到尾?

的另一种方式,你可以编写查询如下:

select t1.id, t2.id from users t1 
join users t2 using (username,password,email) 
where t1.id<t2.id 

这将导致以下解释计划:

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: t1 
     type: ALL 
possible_keys: PRIMARY,users_id_username_password_email 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 16516 
     Extra: 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: t2 
     type: ref 
possible_keys: PRIMARY,users_id_username_password_email 
      key: users_id_username_password_email 
     key_len: 201 
      ref: test.t1.username,test.t1.password,test.t1.email 
     rows: 82 
     Extra: Using where 

它仍然是用户表的一个表扫描,但它不必对整个表进行排序以找到重复项。它只需要做一次关键的查找。

对于它的价值,我只在(username(64),email(64),password(64))指数测试。不需要在索引中包含id,因为所有InnoDB索引都隐含地包含主键列。


这里的另一个查询,通过最小的ID依赖于连接,以减少结果集,然后组和显示更高的ID所愚弄。或者您也可以返回您加入的列。

select t1.id, /* t1.username, t1.password, t1.email, */ group_concat(t2.id) as dupes 
from users t1 
join users t2 
    on (t1.username,t1.password,t1.email) = (t2.username,t2.password,t2.email) 
    and t1.id < t2.id 
left outer join users t3 
    on (t1.username,t1.password,t1.email) = (t3.username,t3.password,t3.email) 
    and t1.id > t3.id 
where t3.id is null 
group by t1.id; 
+0

这看起来像我正在寻找的解决方案,但它不会产生我期望的输出。在有2个条目的情况下,它可以很好地工作,但在第三个条目中添加“t1.id”与第一个结果中的“t2.id”相同。是否有可能使't1.id'始终是重复项的最低可能值?如果你愿意,我可以在聊天中多解释一下。 –