Тюнинг подзапроса в postgres - PullRequest
1 голос
/ 15 мая 2011

Я обнаружил некоторые подозрительные данные в базе данных.Я пытаюсь определить, является ли определенное поле, фамилия, правильным.Я создал следующий запрос в postgres:

SELECT members."memberID", 
       members.lastname 
  FROM members 
 WHERE members."memberID" NOT IN (SELECT members."memberID" 
                                    FROM members 
                                   WHERE members.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*');

В настоящее время подзапрос сопоставляется с обычными именами и именами с гипсом.В родительском запросе должны отображаться элементы, которые не соответствуют этому шаблону.В настоящее время выполнение запроса занимает невероятное количество времени (я никогда не видел его завершенным).Я не уверен, почему это занимает так много времени или как его улучшить.

Ответы [ 2 ]

3 голосов
/ 15 мая 2011

НЕ СУЩЕСТВУЕТ

SELECT m."memberID", 
       m.lastname 
  FROM MEMBERS m 
 WHERE NOT EXISTS (SELECT NULL
                     FROM MEMBERS b
                    WHERE b.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*'
                      AND b."memberID" = m."memberID");

ВЛЕВО СОЕДИНЯЕТСЯ / НУЛЬ

   SELECT m."memberID", 
          m.lastname 
     FROM MEMBERS m 
LEFT JOIN MEMBERS b ON b."memberID" = m."memberID"
                   AND b.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*'
    WHERE b."memberID" IS NULL

Резюме

Цитата :

PostgreSQL одинаково обрабатывает LEFT JOIN и NOT EXISTS, используя один и тот же план выполнения для обоих (а именно Hash Anti Join для примера выше).

Что касается NOT IN, который семантически отличается, посколькуего логика трехвалентна, и он может возвращать NULL, PostgreSQL пытается принять это во внимание и ограничивается использованием фильтра против подплана (хешированный подплан для хешируемого набора результатов, как в примере выше).

Поскольку это необходимодля поиска в хеш-таблице каждого пропущенного значения дважды (первый раз, чтобы найти значение, второй раз, чтобы найти NULL), этот метод немного менее эффективен.

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

Вот почему в PostgreSQL 8.4 один примерld всегда используйте LEFT JOIN / IS NULL или NOT EXISTS вместо NOT IN для поиска пропущенных значений.

Addendum

Но, как отмечает Эндрю Лазарь, если нет дубликатовmemberid в таблице MEMBERS, запрос должен быть только:

SELECT m."memberID", 
       m.lastname 
  FROM MEMBERS m 
 WHERE b.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*'
2 голосов
/ 16 мая 2011

Мне нравится ответ OMG Ponies, но , если memberID уникален (т. Е. PK), вы можете просто удалить подзапрос.

SELECT members."memberID", 
       members.lastname 
  FROM members 
 WHERE members.lastname !~ '[a-zA-Z]+([-][a-zA-Z]+)*';

(я удалил регистронезависимый оператор, поскольку регулярное выражение охватывает оба случая.)

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