Access SQL distinct 去重失效问题

在使用Access数据库进行数据去重时遇到一个问题,当使用包含备注类型字段并结合LEFT JOIN时,发现DISTINCT关键字无法正常工作。经过排查,确认这是一个Access特有的BUG,并给出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天碰到一个很奇怪的问题,开发的一个考试系统采用Access数据库作为题库,里面建了类似下面这样的临时表用于导入Excel格式的题库:

 

临时表
ID(自增,长整型)专业(文本)科目(文本)题型(文本)正文(备注)正文哈希(长整型)
1计算机数学单选题AAAFF
2计算机数学单选题BBBCC
3信息工程数学单选题AAAFF
4信息工程数学单选题CCCDD

 

先在Access 2007中创建了这样结构的一个空表,然后将Excel题库导入该表的专业、科目、题型、正文字段,再通过自定义的一个函数通过正文字段计算出正文哈希字段,如上表所示,随后通过SQL语句:

 

SELECT DISTINCT 正文, 正文哈希 FROM 临时表 AS A LEFT JOIN 问题正文表 AS B ON A.正文哈希=B.正文哈希 WHERE A.正文=B.正文


去重时却发现DISTINCT去重失效了,如上面的表中,ID为1和3的行正文和正文哈希均完全相同,但却仍然两个都显示出来了,尝试了很久才发现是因为正文哈希字段设置了索引,导致DISTINCT失效,去掉该字段的索引就恢复正常了,但不知道为什么索引会影响DISTINCT去重。

PS:问题原因找到了,确认这是Access的一个BUG,触发条件为 正文字段为备注 (Memo)、使用 LEFT JOIN (子查询)时有时就会出现,解决办法为在出现BUG的语句后再添加一个WHERE子句,例如

SELECT DISTINCT 正文, 正文哈希 FROM 临时表 AS A LEFT JOIN 问题正文表 AS B ON A.正文哈希=B.正文哈希 WHERE A.正文=B.正文 AND (A.正文哈希=0 OR A.正文哈希<>0)

可以HACK掉这个BUG

### Oracle 中 TABLE ACCESS FULL 的操作与优化 #### 工作原理 当 Oracle 数据库执行 `TABLE ACCESS FULL` 时,意味着它正在对整个表进行全表扫描。这种访问方式适用于需要检索大量数据的情况,或者在无法利用索引的情况下[^3]。具体来说: - **全表扫描**是指数据库引擎逐行读取表中的所有记录,并逐一检查这些记录是否满足 SQL 查询中的 WHERE 条件。 - 如果查询的结果集较大(通常超过表总数据量的 5%-10%),则全表扫描可能比索引访问更高效。 然而,在某些情况下,全表扫描可能会导致性能瓶颈,尤其是在处理大容量数据表时。 --- #### 优化方法 以下是针对 `TABLE ACCESS FULL` 的几种常见优化策略: 1. **收集统计信息** 确保目标表及其关联对象(如索引)具有最新的统计信息。如果统计信息过期或缺失,可能导致优化器错误估计成本并选择次优方案。可以使用以下命令更新统计信息: ```sql EXEC DBMS_STATS.GATHER_TABLE_STATS('schema_name', 'table_name'); ``` 2. **创建合适的索引** 当查询条件中有高过滤度列时,应为其创建索引以减少不必要的全表扫描。例如,对于频繁用于筛选的字段,可考虑建立 B-tree 或位图索引。注意避免因字段类型转换而导致索引失效[^2]。 3. **调整分区结构** 对于超大规模表格,采用分区技术能够显著降低单次 I/O 开销。合理设计分区键可以使部分查询仅需访问特定分区内少量数据页即可完成计算任务。 4. **组织物理存储布局** 随着时间推移,磁盘碎片化现象不可避免地影响随机读写效率。因此定期维护表空间非常要。可以通过如下语句实现迁移组动作: ```sql ALTER TABLE table_name MOVE TABLESPACE new_tablespace; ANALYZE TABLE table_name COMPUTE STATISTICS; ``` 5. **审查SQL逻辑表达式** 检查是否有隐含的数据类型转换问题存在,因为这往往会造成原本有效的索引变得不可用。比如字符串拼接运算符前后参数不一致等情况均有可能触发该类异常行为。 6. **控制缓存命中率** 提升缓冲池利用率有助于缓解硬盘I/O压力。适当增大SGA区域尺寸以及配置恰当的工作区大小均可带来正面效果。 7. **启用并行处理机制** 若硬件资源配置允许,则开启多线程并发模式亦不失为一种有效途径来加速大数据集合上的复杂运算过程。 8. **评估HINT提示作用** 在特殊场景下可通过手动指定执行路径的方式绕开默认规则限制。不过需要注意的是滥用此类干预措施反而容易引发更多意想不到的新麻烦。 --- ### 示例代码展示如何改善全表扫描情况下的表现 假设我们有一张名为 `orders` 的订单明细清单表,其中包含数百万条历史交易记录。现在我们需要找出最近一个月内的活跃客户群体名单。原始版本可能存在低效之处: ```sql SELECT DISTINCT customer_id FROM orders WHERE order_date >= TO_DATE('2023-09-01','YYYY-MM-DD'); ``` 为了提高响应速度可以从以下几个方面入手改进: 1. 添加覆盖索引来支持快速定位日期范围; 2. 修改函数调用位置以便保留原有索引可用性; 3. 利用临时中间结果暂存阶段成果从而简化最终输出流程。 修订后的脚本形式如下所示: ```sql CREATE INDEX idx_orders_orderdate ON orders(order_date); WITH recent_customers AS ( SELECT /*+ INDEX(orders idx_orders_orderdate) */ customer_id FROM orders o WHERE o.order_date BETWEEN TRUNC(SYSDATE)-30 AND SYSDATE ) SELECT rc.customer_id FROM recent_customers rc; ``` 上述改动不仅明确了期望使用的索引名称还规避掉了动态解析带来的额外负担。 --- 问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值