1

contact次の構造で名前が付けられたテーブルがあるとします。

id INT -- primary key,autoincrement,index 
firstname VARCHAR (255),
lastname VARCHAR(255),
type ENUM

そのようなクエリを実行する:

SELECT c1.id AS c1_id, c2.id AS c2_id
FROM contact c1
INNER JOIN contact c2 ON c1.firstname = c2.firstname AND c1.lastname = c2.lastname
WHERE c1.id <> c2.id AND c1.type=c2.type

少量のレコードでは問題ありません...しかし、レコード数が30〜40から1000に増えると、このクエリは非常に遅くなります.レコード数から抽象化し、このクエリを可能な限り高速化する必要があります.何か提案はありますか?

4

3 に答える 3

4

次のようなもので試すことができます:

SELECT GROUP_CONCAT(DISTINCT id), firstname, lastname
FROM contact
GROUP BY firstname, lastname
HAVING COUNT(DISTINCT id)>1

これにより、重複したすべての名前が返されます。ID が必要な場合は、JOIN を使用できます。

SELECT
  contact.id
FROM
  contact INNER JOIN (SELECT firstname, lastname
                      FROM contact
                      GROUP BY firstname, lastname
                      HAVING COUNT(DISTINCT id)>1) dup
  ON contact.firstname=dup.firstname AND contact.lastname=dup.lastname
于 2013-11-13T10:13:54.257 に答える
1

「<>」を除いて、クエリは問題ありません (実際、提案された代替手段よりもわずかに高速である可能性さえあります!)。いくつかの作業が必要なのはインデックスだけです...

 CREATE TABLE contact
 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
 ,firstname VARCHAR(255) NOT NULL
 ,lastname VARCHAR(255) NOT NULL
 ,type ENUM('small','medium','large') NOT NULL
 );

 INSERT INTO contact VALUES
 (NULL,'John','Brown','small'),
 (NULL,'Bill','Red','small'),
 (NULL,'Paul','Orange','medium'),
 (NULL,'Mike','Green','large'),
 (NULL,'John','Scarlet','small'),
 (NULL,'John','Cyan','medium'),
 (NULL,'Fiona','Brown','large'),
 (NULL,'John','Brown','small'),
 (NULL,'Chris','Copper','medium'),
 (NULL,'Steve','Silver','large');

 INSERT INTO contact SELECT NULL,x.firstname, y.lastname, z.type FROM contact x, contact y, contact z;

SELECT COUNT(*) FROM contact;
+----------+
| COUNT(*) |
+----------+
|     1010 |
+----------+
1 row in set (0.01 sec) 

 SELECT c1.id c1_id
      , c2.id c2_id
   FROM contact c1
   JOIN contact c2 
     ON c1.firstname = c2.firstname 
    AND c1.lastname = c2.lastname
    AND c1.type=c2.type
  WHERE c1.id < c2.id; 

  ...
  ...
  |  1006 |  1008 |
  +-------+-------+
  5634 rows in set (0.16 sec)

それでは、(firstname,lastname,type) にインデックスを追加しましょう...

 DROP TABLE IF EXISTS contact;

 CREATE TABLE contact
 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
 ,firstname VARCHAR(255) NOT NULL
 ,lastname VARCHAR(255) NOT NULL
 ,type ENUM('small','medium','large') NOT NULL
 ,INDEX(firstname,lastname,type)
 );

 INSERT INTO contact VALUES
 (NULL,'John','Brown','small'),
 (NULL,'Bill','Red','small'),
 (NULL,'Paul','Orange','medium'),
 (NULL,'Mike','Green','large'),
 (NULL,'John','Scarlet','small'),
 (NULL,'John','Cyan','medium'),
 (NULL,'Fiona','Brown','large'),
 (NULL,'John','Brown','small'),
 (NULL,'Chris','Copper','medium'),
 (NULL,'Steve','Silver','large');

 INSERT INTO contact SELECT NULL,x.firstname, y.lastname, z.type FROM contact x, contact y, contact z;

 SELECT c1.id c1_id
      , c2.id c2_id
   FROM contact c1
   JOIN contact c2 
     ON c1.firstname = c2.firstname 
    AND c1.lastname = c2.lastname
    AND c1.type = c2.type
    AND c1.id < c2.id; 

  |   775 |   776 |
  ...
  |  1006 |  1008 |
  +-------+-------+
  5634 rows in set (0.05 sec)
于 2013-11-13T10:30:45.530 に答える
1

fthiellaの回答からのわずかな逸脱(これが必要な場合に備えて):

SELECT group_concat(id) as ids, firstname, lastname
FROM contact
GROUP BY firstname, lastname

上記のクエリは、各名と姓の組み合わせの ID のコンマ区切りリストで列 ID を埋めます。

于 2013-11-13T10:17:48.837 に答える