SQL JOIN查找没有具有特定值的匹配记录的记录

时间:2011-01-31 16:18:28

标签: sql mysql join subquery

我正在尝试加速我几年前为我的雇主的购买授权应用程序编写的代码。基本上我有一个SLOW子查询,我想用JOIN替换(如果它更快)。

当导演登录应用程序时,他会看到他尚未授权或拒绝的购买请求列表。使用以下查询生成该列表:

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

sa_order中只有大约900条记录,sa_signature中只有1800条记录,此查询仍需要大约5秒钟才能执行。我已经尝试使用LEFT JOIN来检索我需要的记录,但是我只能在sa_signature中获得没有匹配记录的sa_order记录,并且我需要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 个答案:

答案 0 :(得分:3)

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 :(得分:1)

您可以使用EXISTS替换[NOT] IN运算符以提高性能。

所以你会:

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/

答案 2 :(得分:0)

以下查询应该有效,但我怀疑您的真正问题是您没有适当的索引。您应该在ORDER_ID列的SA_SGINATURES表上有一个索引。

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;

答案 3 :(得分:0)

从sa_order中选择*作为内部联接sa_signature为o.orderid = sa.orderid上的s和sa.type ='administrative director'

另外,您可以在sa_signature表

中的类型上创建非聚集索引

甚至更好 - 拥有一个包含typeid和typename的类型的主表,然后将类型保存为整数,而不是将类型保存为sa_signature表中的文本。那是因为在整数上计算比在文本上计算更快