2012-10-21 79 views
1

这是我的设置:如何选择一个表中的记录,但不是多个PKID的记录?

records包含多个(多于两个)PKID列以及其他一些列。

cached_records只有两列,它们与records中的两个PKID相同。

例如,我们假设records具有PKID'keyA','keyB'和'keyC',而cached_records只有'keyA'和'keyB'。

我需要从records表中取出合适的PKID(如'keyA'和'keyB')不在cached_records表中的行。

如果我只有一个PKID的工作,我知道这个任务是多么的简单:

SELECT 
    pkid 
FROM 
    records 
WHERE 
    pkid NOT IN (SELECT pkid FROM cached_records) 

然而,事实上,在两个PKIDs意味着我不能用一个简单的NOT IN。这是我目前有:

SELECT 
    `keys`.`keyA` AS `keyA`, 
    `keys`.`keyB` AS `keyB` 
FROM 
    (
     SELECT DISTINCT 
      `keyA`, 
      `keyB` 
     FROM 
      `records` 
    ) AS `keys` 
     LEFT JOIN 
       `cached_records` AS `cached` 
      ON 
        `keys`.`keyA` = `cached`.`keyA` 
       AND 
        `keys`.`keyB` = `cached`.`keyB` 
WHERE 
    (
      `cached`.`keyA` IS NULL 
     AND 
      `cached`.`keyB` IS NULL 
    ) 

(该DISTINCT是必要的,因为,因为我只是从records表抓住两个多PKIDs的,有可能是重复的,我真的不需要重复;“keyC '没有被使用,它有助于确定记录的唯一性)。上面的查询工作得很好,但是,随着cached_records表增长,查询需要更长和更长的时间来处理(我们现在正在谈论分钟,有时需要足够长的时间才能让代码挂起并崩溃)。

所以,我想知道什么是最有效的方式来做这种操作(从一个表中选择行不存在于另一个表中的行)与多个PKIDS而不是只有一个...

回答

2

这应该是更快:

SELECT DISTINCT 
    `records`.`keyA` AS `keyA`, 
    `records`.`keyB` AS `keyB` 
FROM 
    `records` 
     LEFT JOIN 
       `cached_records` AS `cached` 
      ON 
        `records`.`keyA` = `cached`.`keyA` 
       AND 
        `records`.`keyB` = `cached`.`keyB` 
WHERE 
      `cached`.`keyA` IS NULL -- one is enough here 

注:

  • 与查询的表,你失去了很多的性能。您可以在这里选择最外面的SELECT。
  • 就足够了检查两个键中的一个,如果他们是空的,因为没有人可以为空
  • 你应该确认keyAkeyB列属于同一类型的,并没有转换发生(在工作见过这样的实时代码...)
  • 您应该在表上有适当的索引。这个查询的分钟是一些可怕的事情的迹象...(或疯狂的数据量)
+1

我实施了一些建议,但这是杀手:他们的钥匙是不同的类型! (我认为我已经修复了这个问题,但是在倾倒和恢复不同的数据库转储时,我想我最终使用了一个没有固定的转储...),所以我加入了一个pkids作为整数的表,其他作为varchars。 – jzimmerman2011

+0

为什么是杀手?无法例如'records.keyA = CAST(cached.keyA AS INTEGER)'解决这个问题? –

+0

@TerjeD它甚至不需要,MySQL为你做。问题不在于**不能正常工作**,而是因为它非常麻烦。 – ppeterka

相关问题