关于数据去重(distinct)

本文介绍了一种在SQL查询中使用DISTINCT关键字去除重复记录的方法,并通过具体示例展示了如何在分页查询中正确应用数据去重,确保查询结果的准确性。

数据去重SQL:

//DISTINCT对下面的字段进行去重
hqlStr.append(" 
SELECT DISTINCT
si.DOCTOR_ID,SI.PATIENT_ID,ME.NAME,ME.ID_NUMBER,
ME.GENDER_CODE,ME.PHONE_NUM,ME.BIRTHDAY,
ME.MEMBER_PHOTO,ME.UNIT_ID,
ME.ASSIGNED_FLAG  
FROM T_SIGN_CONTRACT si,T_MEMBER me 
WHERE si.PATIENT_ID=ME.MEMBER_ID  
AND si.DOCTOR_ID='"+ doctorId + "'");

service实现层的方法代码如下:

public PagerModel findMemberByDoctorId(SignContractDto dto){
     PagerModel pagerModel = dto.getPageModel();
     if(pagerModel==null){
        pagerModel = new PagerModel();
        dto.setPageModel(pagerModel);
        }
        //调用DAO 拼接查询条件
        signContractDao.buildPagerModelQuery(dto);
        //调用分页查询方法
        commonService.fillSqlPagerModelData(pagerModel,FindMyMemberVo.class,"SI.DOCTOR_ID");
        return pagerModel;
    }

这里有个问题,就是dao层中的数据去重,但是在commonService中的分页查询公共方法没有去重,所以会出现pagedata的数据可能会与totals中的数据不同(在有数据重复的情况下)。

修改方法:

    public PagerModel findMemberByDoctorId(SignContractDto dto){
        PagerModel pagerModel = dto.getPageModel();
        if(pagerModel==null){
            pagerModel = new PagerModel();
            dto.setPageModel(pagerModel);
        }
        //调用DAO 拼接查询条件
        signContractDao.buildPagerModelQuery(dto);
        //调用分页查询方法
        commonService.fillSqlPagerModelData(pagerModel,FindMyMemberVo.class,"distinct(SI.PATIENT_ID)");
        return pagerModel;
    }

在fillSqlPagerModelData的第三个参数写上要去重的条件distinct(SI.PATIENT_ID)(这里不是写主键!)

<think>我们正在讨论SQL中DISTINCT关键字的原理。根据用户的问题,需要详细解释DISTINCT如何工作,包括其内部机制和优化考虑。同时,参考了提供的引用内容。 引用[1]指出:DISTINCT用于从查询结果中复记录,在报告生成、数据分析和用户查询中至关要。 引用[2]提到:Distinct关键字过滤多余的复记录只保留一条,但通常只用于返回不复记录的条数,而不是返回所有值,因为其效率问题(二循环查询)。 引用[3]是关于MySql执行计划(Explain关键字)的,虽然不直接解释DISTINCT原理,但我们可以联想到通过执行计划来分析DISTINCT的执行过程。 因此,回答将围绕以下方面展开: 1. DISTINCT的基本用法和效果 2. DISTINCT的工作原理(内部机制) 3. 性能问题和优化方法(结合执行计划) 另外,根据用户要求,我们需要使用LaTeX格式的数学表达式(虽然DISTINCT原理不涉及复杂数学,但如果有排序等操作,可以适当使用),并生成相关问题。 回答结构: 1. 概述DISTINCT的作用 2. 详细解释工作原理(包括排序、哈希两种常见实现) 3. 讨论性能优化(使用索引、避免SELECT *等) 4. 示例和实际执行计划分析(可选) 5. 总结 最后,生成相关问题。</think>### SQL DISTINCT 关键字的工作原理详解 #### **1. 基本作用与语法** `DISTINCT` 用于消除查询结果中**所有列值完全相同的复行**,返回唯一记录集合。语法: ```sql SELECT DISTINCT 列1, 列2, ... FROM 表名; ``` - 若未指定列,则对所有列(`SELECT DISTINCT *`) - 仅作用于查询结果,不修改原始数据[^1] #### **2. 核心原理:基于排序与哈希的** 数据库引擎通常通过两种方式实现: - **排序(Sort-Based Deduplication)** 1. 将查询结果按所有列**全排序**(如快速排序) 2. 遍历有序数据:若当前行与前一行**所有列值相等**,则丢弃 3. 时间复杂度:$O(n \log n)$(排序成本)+ $O(n)$(遍历成本) 例:结果集 `[(A,1), (A,1), (B,2)]` → 排序后遍历 → 输出 `[(A,1), (B,2)]` - **哈希(Hash-Based Deduplication)** 1. 为每行计算**哈希值**(如 MD5 或自定义哈希函数) 2. 使用哈希表(Hash Table)存储唯一键: - 若哈希值不存在 → 保留行并记录哈希值 - 若哈希值已存在 → 丢弃(视为复) 3. 时间复杂度:$O(n)$(理想情况下),但需处理哈希冲突 #### **3. 关键特性与限制** - **隐式排序问题** 部分数据库(如 MySQL)的 `DISTINCT` 可能隐式触发排序操作,影响性能。可通过 `EXPLAIN` 验证: ```sql EXPLAIN SELECT DISTINCT name FROM users; -- 观察 Extra 列是否出现 "Using temporary" ``` 若输出含 `Using filesort`,表明使用了排序[^3] - **空值(NULL)处理** - 所有数据库均将 **NULL 视为相等** - 例:`SELECT DISTINCT col` 会将多个 `NULL` 合并为一行 - **与 GROUP BY 的差异** | 特性 | DISTINCT | GROUP BY | |--------------------|------------------------------|------------------------| | 输出结果 | 唯一值列表 | 分组+可搭配聚合函数 | | 性能优化 | 通常无分组聚合优化 | 可利用索引优化分组 | | 语法灵活性 | 仅 | 可结合 SUM/AVG/COUNT 等 | #### **4. 性能优化策略** - **避免 `SELECT *`** 明确指定列减少处理数据量: ```sql -- 低效 SELECT DISTINCT * FROM orders; -- 高效 SELECT DISTINCT order_id, customer_id FROM orders; ``` - **利用索引覆盖查询** 若查询列全部被索引覆盖,可避免全表扫描: ```sql CREATE INDEX idx_name ON users(name); SELECT DISTINCT name FROM users; -- 可能直接扫描索引而非数据表 ``` - **大数据集改用 GROUP BY** 当数据量极大时,`GROUP BY` 可能比 `DISTINCT` 更快(尤其有索引时): ```sql SELECT name FROM users GROUP BY name; -- 可能比 DISTINCT 高效 ``` - **限制结果集范围** 通过 `WHERE` 或 `LIMIT` 减少处理行数: ```sql SELECT DISTINCT product_id FROM sales WHERE sale_date > '2023-01-01' LIMIT 1000; ``` #### **5. 实际执行过程示例** 假设表 `employees`: | id | name | dept | |----|-------|------| | 1 | Alice | HR | | 2 | Bob | IT | | 3 | Alice | HR | 执行 `SELECT DISTINCT name, dept FROM employees`: 1. **数据读取**:加载所有行 2. **计算**(以排序法为例): - 原始数据:`[(Alice,HR), (Bob,IT), (Alice,HR)]` - 排序后:`[(Alice,HR), (Alice,HR), (Bob,IT)]` - 遍历:保留第1行 `(Alice,HR)`,跳过第2行(复),保留第3行 `(Bob,IT)` 3. **输出结果**: | name | dept | |-------|------| | Alice | HR | | Bob | IT | > ⚠️ 注意:`DISTINCT` 在子查询或 JOIN 中可能导致意外行为,需结合 `EXPLAIN` 分析执行计划[^3]。 --- ### 总结 `DISTINCT` 通过**排序或哈希**算法实现,核心是识别并移除所有列值完全相同的行。其效率取决于数据规模、索引设计及列数量,**大数据集需谨慎使用**。优化时优先考虑指定列、利用索引、添加过滤条件,必要时改用 `GROUP BY`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值