SQL JOIN для поиска записей, которые не имеют совпадающих записей с определенным значением - PullRequest
3 голосов
/ 31 января 2011

Я пытаюсь ускорить некоторый код, который я написал несколько лет назад для приложения авторизации покупки моего работодателя. В основном у меня есть SLOW подзапрос, который я хотел бы заменить на JOIN (если это быстрее).

Когда директор входит в приложение, он видит список запросов на покупку, которые ему еще предстоит авторизовать или отклонить. Этот список создается с помощью следующего запроса:

SELECT * FROM SA_ORDER WHERE ORDER_ID NOT IN
    (SELECT ORDER_ID FROM SA_SIGNATURES WHERE TYPE = 'administrative director');

В sa_order есть только около 900 записей и 1800 записей в sa_signature, и выполнение этого запроса по-прежнему занимает около 5 секунд. Я попытался использовать LEFT JOIN для получения нужных мне записей, но я смог получить только записи sa_order без соответствующих записей в sa_signature, и мне нужны записи sa_order с «нет соответствующих записей типа« административный директор » ». Ваша помощь очень ценится!

Схема для двух таблиц следующая:

Таблицы имеют следующий формат:

CREATE TABLE sa_order
(
    `order_id`        BIGINT       PRIMARY KEY AUTO_INCREMENT,
    `order_number`    BIGINT       NOT NULL,
    `submit_date`     DATE         NOT NULL,
    `vendor_id`       BIGINT       NOT NULL,
    `DENIED`          BOOLEAN      NOT NULL DEFAULT FALSE,
    `MEMO`            MEDIUMTEXT,
    `year_id`         BIGINT       NOT NULL,
    `advisor`         VARCHAR(255) NOT NULL,
    `deleted`         BOOLEAN      NOT NULL DEFAULT FALSE
);

CREATE TABLE sa_signature
(
    `signature_id`        BIGINT          PRIMARY KEY AUTO_INCREMENT,
    `order_id`            BIGINT          NOT NULL,
    `signature`           VARCHAR(255)    NOT NULL,
    `proxy`               BOOLEAN         NOT NULL DEFAULT FALSE,
    `timestamp`           TIMESTAMP       NOT NULL DEFAULT NOW(),
    `username`            VARCHAR(255)    NOT NULL,
    `type`                VARCHAR(255)    NOT NULL
);

Ответы [ 4 ]

3 голосов
/ 31 января 2011

Создать индекс для sa_signatures (type, order_id).

Нет необходимости преобразовывать запрос в LEFT JOIN, если только sa_signatures не разрешает пустые значения в order_id.С индексом, NOT IN также будет работать.Однако, на всякий случай, если вам интересно:

SELECT  o.*
FROM    sa_order o
LEFT JOIN
        sa_signatures s
ON      s.order_id = o.order_id
        AND s.type = 'administrative director'
WHERE   s.type IS NULL

Вы должны выбрать столбец NOT NULL из sa_signatures, чтобы предложение WHERE работало хорошо.

1 голос
/ 31 января 2011

Вы можете заменить оператор [NOT] IN на EXISTS для повышения производительности.

Итак, у вас будет:

SELECT * FROM SA_ORDER WHERE NOT EXISTS
    (SELECT ORDER_ID FROM SA_SIGNATURES
     WHERE TYPE = 'administrative director'
       AND ORDER_ID = SA_ORDER.ORDER_ID);

Причина: «При использовании« NOT IN »запрос выполняет полное сканирование вложенных таблиц, тогда как для« NOT EXISTS »запрос может использовать индекс внутри подзапроса.»

Источник: http://decipherinfosys.wordpress.com/2007/01/21/32/

0 голосов
/ 31 января 2011

выберите * из sa_order как o внутреннее объединение sa_signature как s для o.orderid = sa.orderid и sa.type = 'административный директор'

также вы можете создать некластеризованный индекс для типа в sa_signaturetable

еще лучше - иметь основную таблицу для типов с typeid и typename, а затем вместо того, чтобы сохранять тип как текст в вашей таблице sa_signature, просто сохранить тип как целое число.это потому, что вычисления на целых числах намного быстрее, чем вычисления на тексте

0 голосов
/ 31 января 2011

Этот следующий запрос должен работать, однако я подозреваю, что ваша реальная проблема в том, что у вас нет нужных индексов.У вас должен быть индекс для таблицы SA_SGINATURES в столбце ORDER_ID.

SELECT * 
FROM 
SA_ORDER 
LEFT JOIN
SA_SIGNATURES
ON
SA_ORDER.ORDER_ID = SA_SIGNATURES.ORDER_ID AND
TYPE = 'administrative director'
WHERE 
SA_SIGNATURES.ORDER_ID IS NULL;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...