2011-12-01 65 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'始終是重複項的最低可能值?如果你願意,我可以在聊天中多解釋一下。 –