# [Know Issue] Update 0 rows 后查到重复数据

## Key Words

UnionScan,Update

## Description

执行 update 后返回 Query OK, 0 rows affected 后，select 查询到重复数据

```SQL
/* t */ drop table if exists t;
/* t */ create table t (a varchar(10) primary key nonclustered, b varchar(10));
/* t */ insert into t values ('a', 'b');
/* t */ begin;
/* t */ select a from t; -- [a]
/* t */ update t set b = 'b' where a = 'a';
/* t */ select a from t; -- [a, a]
/* t */ commit;
```

## Root Cause

为了解决 Lock 记录堆积的问题，[#25730](https://github.com/pingcap/tidb/pull/25730) 会将 lock 转成 put 并写 mem buffer 。因此，上例中 update 虽然不作任何修改，但会写一条 uk 键值对到 mem buffer，即 put(t{tid}_i{'a'}, handle)。随后 select 通过 UnionScan -> IndexReader 路径去读：UnionScan 取 snapshot row 时，因为 handle -> row_data 并不 mem buffer 中，所以不会过滤掉 IndexReader 读到的数据；UnionScan 取 added row 时是从 mem index reader 中构造出来，也就包含 update 时 lock -> put 写入的数据，进而导致读出重复数据。

## Resolution

该问题主因在 [#25730](https://github.com/pingcap/tidb/pull/25730) ，而 Lock 记录堆积在新版本 (>=v6.5.0) 中有了更好的方案。对于较老版本，则可以通过如下方式 workaround：

- 通过 optimizer hint 选择其它执行计划，规避有问题的读路径
- 使用 clustered index 作为主键，避免 UnionScan 无法 merge 的情况

## Affected Versions

- v5.1.1 及以上版本
- < v5.1.0 && >= v5.0.4
- < v5.0.0 && >= v4.0.14
