如何以有效的方式摆脱 mysql table 列表中的冗余
How to get rid of redundancy in a mysql table with lists in an efficient way
前段时间做了一个快速的MVP,现在已经成为比较现实的项目了。现在我正在重构和改进它。我有一个这样的table
CREATE TABLE `records` (
`id` int(11) NOT NULL,
`type` int(11) NOT NULL,
.....
`ref` int(11) DEFAULT NULL,
`enabled` tinyint(1) NOT NULL DEFAULT '1',
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `mrecord`
ADD PRIMARY KEY (`id`),
ADD KEY `type` (`type`);
ADD KEY `ref` (`ref`);
ref
是对先前 id
的引用,如果 none 和 enabled
则为 null 让我知道此项是否是该类型的最后一个版本。关键是,当一个项目类型 X 被替换为一个新的时,旧的将被禁用(enabled
= 0)并且新的将 ref
设置为旧的 id
.
例如,我们 table 包含 3 种类型的项目:
--------------------------------------------
| ID | type | other columns | ref | enabled |
|--------------------------------------------|
| 1 | 1 | | null | 1 |
| 2 | 2 | | null | 1 |
| 3 | 3 | | null | 1 |
--------------------------------------------
现在我们添加一个新的项目版本来替换项目类型 2:
--------------------------------------------
| ID | type | other columns | ref | enabled |
|--------------------------------------------|
| 1 | 1 | | null | 1 |
| 2 | 2 | | null | 0 |
| 3 | 3 | | null | 1 |
| 4 | 2 | | 2 | 1 |
--------------------------------------------
如果我们更新我们拥有的全新项目:
--------------------------------------------
| ID | type | other columns | ref | enabled |
|--------------------------------------------|
| 1 | 1 | | null | 1 |
| 2 | 2 | | null | 0 |
| 3 | 3 | | null | 1 |
| 4 | 2 | | 2 | 0 |
| 5 | 2 | | 4 | 1 |
--------------------------------------------
我们这里有仅启用最新版本的项目类型列表。
但是这里的 enabled
列是多余的,因为启用的项目只是没有新版本的项目。
所以我的问题是如何做一个 SQL 查询相当于:
SELECT * FROM `records` WHERE type='2' AND enabled='1'
不使用 enabled
并且以高效的方式(此查询 <1ms)。
对于此查询,您需要在出现在 where 子句中的两列上建立索引:
create index myidx on records(type, enabled);
有了索引,数据库应该能够高效地执行查询。您可能还想尝试反转列顺序,看看它是否会提高性能。
您可以使用 not exists
:
select r.*
from records r
where not exists (select 1
from records r2
where r2.ref = r.id
) and
r.type = 2;
但是,在我看来,enabled
的使用使代码更加清晰。性能需要 records(ref)
上的索引。
如果您假设 id 总是递增的,您也可以使用最大的 id
。
前段时间做了一个快速的MVP,现在已经成为比较现实的项目了。现在我正在重构和改进它。我有一个这样的table
CREATE TABLE `records` (
`id` int(11) NOT NULL,
`type` int(11) NOT NULL,
.....
`ref` int(11) DEFAULT NULL,
`enabled` tinyint(1) NOT NULL DEFAULT '1',
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `mrecord`
ADD PRIMARY KEY (`id`),
ADD KEY `type` (`type`);
ADD KEY `ref` (`ref`);
ref
是对先前 id
的引用,如果 none 和 enabled
则为 null 让我知道此项是否是该类型的最后一个版本。关键是,当一个项目类型 X 被替换为一个新的时,旧的将被禁用(enabled
= 0)并且新的将 ref
设置为旧的 id
.
例如,我们 table 包含 3 种类型的项目:
--------------------------------------------
| ID | type | other columns | ref | enabled |
|--------------------------------------------|
| 1 | 1 | | null | 1 |
| 2 | 2 | | null | 1 |
| 3 | 3 | | null | 1 |
--------------------------------------------
现在我们添加一个新的项目版本来替换项目类型 2:
--------------------------------------------
| ID | type | other columns | ref | enabled |
|--------------------------------------------|
| 1 | 1 | | null | 1 |
| 2 | 2 | | null | 0 |
| 3 | 3 | | null | 1 |
| 4 | 2 | | 2 | 1 |
--------------------------------------------
如果我们更新我们拥有的全新项目:
--------------------------------------------
| ID | type | other columns | ref | enabled |
|--------------------------------------------|
| 1 | 1 | | null | 1 |
| 2 | 2 | | null | 0 |
| 3 | 3 | | null | 1 |
| 4 | 2 | | 2 | 0 |
| 5 | 2 | | 4 | 1 |
--------------------------------------------
我们这里有仅启用最新版本的项目类型列表。
但是这里的 enabled
列是多余的,因为启用的项目只是没有新版本的项目。
所以我的问题是如何做一个 SQL 查询相当于:
SELECT * FROM `records` WHERE type='2' AND enabled='1'
不使用 enabled
并且以高效的方式(此查询 <1ms)。
对于此查询,您需要在出现在 where 子句中的两列上建立索引:
create index myidx on records(type, enabled);
有了索引,数据库应该能够高效地执行查询。您可能还想尝试反转列顺序,看看它是否会提高性能。
您可以使用 not exists
:
select r.*
from records r
where not exists (select 1
from records r2
where r2.ref = r.id
) and
r.type = 2;
但是,在我看来,enabled
的使用使代码更加清晰。性能需要 records(ref)
上的索引。
如果您假设 id 总是递增的,您也可以使用最大的 id
。