本帖最后由 roych 于 2015-7-21 16:26 编辑
说到not in,可能会扯出一段陈年往事来。几年前,一个版友提出一个问题:为什么执行左联接删除查询时,总是弹出以下对话框: 在那之前我刚好也遇到过这个问题,后来用子查询完成的,于是便贴上这样的语句: DELETE * FROM 用户动作 WHERE 节点地址 Not In (select 节点地址 from [设备数据]); 正想躲在角落里嘚瑟时,todaynew提出这查询效率较低,应改为域函数查询,例如: DELETE * FROM 用户动作 WHERE DCount("节点地址","设备总表","节点地址='" & [节点地址] & "'")=0; 对比低效率规则,我们的语句各自符合一条。当然,根据前面的介绍,他的语句要好一些,——因为“=”的效率要比“in”高。 为什么说in的效率低呢,那是因为用in的话,每条记录都要去子查询里检索一番,比较的次数相当于两个数据源总记录条数的乘积。而用Dcount效率相对高一些,是因为这相当于进行一次域函数运算,然后再查询。当然,数据量特别多的时候,弊端也是相当明显的。 我们不妨做一个大胆的假想:计算语句效率要比非计算语句的高。那么如果还用not,能不能实现效率高一点的查询呢? 答案是可以的。这就要说说神一样存在着的谓词exists了。它低调得让人感觉不到它的存在,——Access内置函数是找不到的,以至于我一直以为它只存在于另一时空——SQL Server之中。和in不同的是,它返回一个布尔值。 按设想,not exists的效率通常会比not in高。当然,各种情况下并不完全一致,最好还是测试下。 DELETE * FROM 用户动作 WHERE not Exists (select * from 设备数据 where 用户动作.节点地址=设备数据.节点地址); 又到提问时间了。今天的问题是:还有没有比这些更高效的查询呢? ——有,那就是前面版友提出的左联接查询。——这也是todaynew后面给出的语句。 ——打住!前面不是报错了吗? 是的。那为什么会报错呢?我们先来看看这两个表的关联字段。左表的节点地址是多个重复值,右表的也是多个重复值。这样建立起来的关系是什么样的关系?多对多?——如果你这么说,我很怀疑你的access可能是语文老师教的,——多对多的关系是由至少两组一对多关系传递而生成。 所以,说到底,还是表设计的问题。——不懂的又可以去看浅谈范式了。我们这里先抛开这不谈,回到问题上。根据我们前面的剖析,很容易找到解决办法。 先把父表(用户动作)复制一份出来,将节点地址设置为索引(有重复),保存为“用户动作1”。然后把子查询(设备数据)的节点地址复制出来,新建的关系当然不能再像前面那样混乱了,为此,我们只能把唯一值复制出来,于是便有“设备总表”,最后将设备总表的节点地址设置为主键,便可以建立好这个一对多的关系了。至此,我们有: DELETE 用户动作1.* FROM 用户动作1 LEFT JOIN 设备总表 ON 用户动作1.节点地址 = 设备总表.节点地址 WHERE 设备总表.节点地址 Is Null; |