从两个表中选择剩余记录(tableS - tableS)

时间:2014-05-20 12:07:31

标签: mysql

如何选择tableB中存在但不存在于tableA中的记录(基本上就像tableB - tableA)?

我有以下表格:(每张表有100万条记录)

tableA
    id int(11) NOT NULL PRIMARY KEY
    name varchar(50)
    sku varchar(10) index
    description text

tableB
    id int(11) NOT NULL PRIMARY KEY
    stock int(11)
    price int(11)
    sku varchar(10) index

注意:sku已编入索引。

  1. tableA和tableB在sku字段中具有一对一的关系。
  2. 两张表都有1米记录
  3. 我想获取tableB中存在但不存在于tableA中的记录(基本上它就像tableB - tableA)。 LEFT JOIN而不是很糟糕(非常慢)。
  4. 什么可以替代解决方案?

    以下是我尝试的查询:

    LEFT JOIN query:
        SELECT a.sku FROM tableA a
        LEFT JOIN tableB b
           ON a.sku = b.sku 
        WHERE a.sku is NULL
    
    NOT IN query:
        SELECT * from tableB where sku NOT IN (SELECT sku from tableA)
    

2 个答案:

答案 0 :(得分:0)

我认为最好的解决方案是left join或:

select *
from tableB b
where not exists (select 1 from tableA where a.sku = b.sku);

not in解决方案的问题是NULL中的tableA值将导致查询中未返回任何行。

为了提高性能,您需要tableA(sku)上的索引:

create index tableA_sku on tableA(sku);

这将加快left joinnot exists版本的速度。

答案 1 :(得分:0)

准备环境以复制问题:

DELIMITER $$

DROP PROCEDURE IF EXISTS `insertMe` $$
CREATE PROCEDURE insertMe()
BEGIN
 DECLARE i BIGINT DEFAULT 2;
  WHILE (i <= 1000000) DO
   INSERT INTO tableA(id,NAME,sku,description) VALUES(i,CONCAT('name',i),CONCAT('sku',i),CONCAT('description',i));  
   IF(i%2=0) THEN
       INSERT INTO tableB(id,stock,price,sku) VALUES(i,i%10,i%5,CONCAT('sku',i)); 
       END IF;
   SET i=i+1;
 END WHILE;
/*
CALL insertMe();
*/
END $$

DELIMITER ;

CREATE INDEX idx_tableA ON tableA(sku);
CREATE INDEX idx_tableB ON tableB(sku);

您的要求的查询(使用左连接)已在我的测试环境中的1-2Sec中执行(2个具有1G RAM的虚拟CPU)。

@Gordon Linoff提到的左连接查询和查询没有任何问题,我建议按照GordonL的建议通过执行验证索引使用情况。

接下来,我怀疑MYSQL数据库中的陈旧表统计信息是否存在性能问题。请尝试以下脚本,然后查看查询的效果。

ANALYZE TABLE tableA;
ANALYZE TABLE tableB;

最后但同样重要的是,尝试备份/重新创建表及其索引以及上面的分析语句,然后查看查询的性能。它修复了行链和迁移的问题。