Найти строки, которые имеют 3 из 5 общих полей - как ускорить запрос? - PullRequest
1 голос
/ 02 сентября 2011

Запрос ниже работает отлично, но медленно. В таблице из примерно 7500 строк требуется около 30 секунд для выполнения. Как я мог ускорить это?

Цель состоит в том, чтобы найти «почти повторяющиеся» строки в одной и той же таблице. При совпадении 3 из 5 полей у нас есть попадание.

SELECT 
originalTable.id,
originalTable.lastname,
originalTable.firstname,
originalTable.address,
originalTable.city,
originalTable.email

FROM
address as originalTable,
address as compareTable

WHERE

# do not find the same record
originalTable.id != compareTable.id and

# at least 3 out of those 5 should match
(originalTable.firstname = compareTable.firstname) +
(originalTable.lastname = compareTable.lastname)  +
(originalTable.address = compareTable.address and originalTable.address != '')  +
(originalTable.city = compareTable.city and originalTable.city != '')  +
(originalTable.email = compareTable.email and originalTable.email != '')
>= 3


GROUP BY
originalTable.id

ORDER BY
originalTable.lastname asc,
originalTable.firstname asc,
originalTable.city asc

Спасибо за любые советы по оптимизации.

Ответы [ 2 ]

0 голосов
/ 04 сентября 2011

Ваше сравнение, как уже отмечалось, потребует декартовой ... но только частичной. Так как вы требуете значения в полях вашего имени и фамилии, у меня будет индекс по крайней мере по имени, имени. Затем добавьте предложение WHERE в ваше условие только для части фамилии ... скажем, первые 2-3 символа. Таким образом, он будет только декартовым по отношению к тем же префиксам, что и остальные. Нет смысла сравнивать «Билла Джонса» с «Тоней Смит». Тем не менее, вы можете быть заинтересованы в "Билл Джонс" против "Уильям Джонс" по общему адресу, городу и / или электронной почте. Рассмотрим следующие части имени для декартового сравнения.

(names fictitious for sample)
ID  Last     First
1   Adams    Brian
2   Adams    Marsha
3   Andrews  Jeff
4   Brown    Steve
5   Johns    Dave
6   Johnson  Bill
7   Johnson  William

Оба «Адамса» будут сравниваться, если вы укажете только 3 левых каждой фамилии в предложении where. «Эндрюс» и «Браун» не могут сравниться ни с кем другим. Тогда 3, начинающиеся с "Джо", будут проверены на декартову ...

Теперь добавьте еще одно значение MORE к предложению where ... Поскольку у вас есть столбец ID, убедитесь, что он тоже является частью предложения where. Где ID второй таблицы ВСЕГДА больше, чем та, на которой вы находитесь. Пример: при сравнении имен "Адамс". Вы уже будете знать, если ID1 сравнивался с ID2 как дубликат или нет (в данном случае нет), так зачем возвращаться назад и повторно сравнивать ID2 с ID1.

Итак, эта выборка из 7 записей приведет к сравнению

1-2
2-no more to compare against
3-no more to compare against
4-no more to compare against
5-6
5-7
6-7
7-no more to compare against

Таким образом, в конечном итоге будет что-то вроде (включая идентификатор, который был близким совпадением, в качестве основы для просмотра.) Вы можете даже получить все столбцы как «MatchFirstName, MatchLastName, MatchCity и т. Д.» Только для предварительного просмотра. ..)

SELECT 
      originalTable.id,
      originalTable.lastname,
      originalTable.firstname,
      originalTable.address,
      originalTable.city,
      originalTable.email,
      compareTable.ID as MatchID
    FROM
      address as originalTable,
      address as compareTable
    WHERE
          originalTable.ID < CompareTable.ID
      AND left( originalTable.LastName, 3 ) = left( CompareTable.LastName, 3 )
      AND (originalTable.firstname = compareTable.firstname) 
        + (originalTable.lastname = compareTable.lastname) 
        + (originalTable.address = compareTable.address and originalTable.address != '')  
        + (originalTable.city = compareTable.city and originalTable.city != '')  
        + (originalTable.email = compareTable.email and originalTable.email != '') >= 3
0 голосов
/ 04 сентября 2011

Здесь требуется декартово произведение, это правда. Я придумал следующее решение:

CREATE TABLE address_dups(INDEX (is_duplicate)) ENGINE=MEMORY   
SELECT 
  originalTable.id,
  compareTable.id,
(
  (originalTable.firstname = compareTable.firstname) +
  (originalTable.lastname = compareTable.lastname)  +
  (originalTable.address = compareTable.address and originalTable.address != '')  +
  (originalTable.city = compareTable.city and originalTable.city != '')  +
  (originalTable.email = compareTable.email and originalTable.email != '')
  >= 3
) AS is_duplicate
FROM 
address as originalTable,
address as compareTable
WHERE originalTable.id != compareTable.id;

SELECT * FROM address_dups WHERE is_duplicate = 1;

Это даст вам для каждого идентификатора строки нечеткий дубликат строки идентификаторов, которые вы запрашиваете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...