仅针对特定其他列值的一列索引
Index for one column only for specific other column value
我有 table 日志,其中有两个字段:action
(VARCHAR 45) 和 info
(VARCHAR 10000)。
此 table 记录了多项内容,其中之一是访问页面时的用户 ip。对于这种情况 action
='ip', info
='IP.ADD.RE.SS'.
因为 info
可以记录大量特定内容的文本,我只想创建适用于 info
字段的索引 action
='ip' 只有这样我才能快速搜索 IP,并且没有 "actions".
的过度生长的索引
我已经尝试为前 15 个字符创建 INDEX,但 IP 条目仍然大约占所有内容的 1%,这对我来说似乎有点过分了。
整个解决方案都是从别人那里继承来的,不幸的是,我现在无能为力改变整个架构
任何关于如何正确操作的建议?有可能吗?
无论如何,您都是在操作列上进行过滤,因此组合索引是这里的解决方案。在两列 (action, info(15))
.
上创建索引
索引中列的顺序很重要。不要反过来改。
这似乎属于 "EAV" 类别。你有一堆东西(ip、postdel 等),每一个都是可选的。有些需要索引,有些不需要。
我的建议是将键值对放在 JSON
字符串中。并为您想要索引的任何内容(在您的情况下为 IP)创建一个特殊的列。可以NULLable
为了最小化(但不是完全消除'wasted'space.
另见我的blog on EAV。
另请参阅 MySQL 和涉及 JSON 的 MariaDB 实现。注意:它们需要相对较新版本的 MySQL 或 MariaDB。
一些 RDBMS 产品支持您所描述的内容。它被不同的产品称为partial or filtered indexes。
- PostgreSQL 有 partial indexes
- Microsoft SQL 服务器 filtered indexes
- SQL网站有 partial indexes
MySQL 没有实现这个想法(他们没有义务实现它,因为它是一个非标准功能)。已经有人要求将此作为一项新功能:https://bugs.mysql.com/bug.php?id=76631
您可以在 MySQL 5.7 中执行的一种模拟部分索引的解决方法是创建一个值为 NULL 的虚拟列,除非 action
为 'ip'。然后索引该虚拟列:
ALTER TABLE logs
ADD COLUMN ip_info VARCHAR(12)
AS (CASE `action` WHEN 'ip' THEN LEFT(info, 12) END),
ADD KEY (ip_info);
严格来说,这仍然是每一行的索引,但至少它不会将您的任何值存储在索引中,除非操作是 'ip'。
P.S.: 我没有测试过上面的例子,如果有语法错误,请见谅。
我有 table 日志,其中有两个字段:action
(VARCHAR 45) 和 info
(VARCHAR 10000)。
此 table 记录了多项内容,其中之一是访问页面时的用户 ip。对于这种情况 action
='ip', info
='IP.ADD.RE.SS'.
因为 info
可以记录大量特定内容的文本,我只想创建适用于 info
字段的索引 action
='ip' 只有这样我才能快速搜索 IP,并且没有 "actions".
我已经尝试为前 15 个字符创建 INDEX,但 IP 条目仍然大约占所有内容的 1%,这对我来说似乎有点过分了。 整个解决方案都是从别人那里继承来的,不幸的是,我现在无能为力改变整个架构
任何关于如何正确操作的建议?有可能吗?
无论如何,您都是在操作列上进行过滤,因此组合索引是这里的解决方案。在两列 (action, info(15))
.
索引中列的顺序很重要。不要反过来改。
这似乎属于 "EAV" 类别。你有一堆东西(ip、postdel 等),每一个都是可选的。有些需要索引,有些不需要。
我的建议是将键值对放在 JSON
字符串中。并为您想要索引的任何内容(在您的情况下为 IP)创建一个特殊的列。可以NULLable
为了最小化(但不是完全消除'wasted'space.
另见我的blog on EAV。
另请参阅 MySQL 和涉及 JSON 的 MariaDB 实现。注意:它们需要相对较新版本的 MySQL 或 MariaDB。
一些 RDBMS 产品支持您所描述的内容。它被不同的产品称为partial or filtered indexes。
- PostgreSQL 有 partial indexes
- Microsoft SQL 服务器 filtered indexes
- SQL网站有 partial indexes
MySQL 没有实现这个想法(他们没有义务实现它,因为它是一个非标准功能)。已经有人要求将此作为一项新功能:https://bugs.mysql.com/bug.php?id=76631
您可以在 MySQL 5.7 中执行的一种模拟部分索引的解决方法是创建一个值为 NULL 的虚拟列,除非 action
为 'ip'。然后索引该虚拟列:
ALTER TABLE logs
ADD COLUMN ip_info VARCHAR(12)
AS (CASE `action` WHEN 'ip' THEN LEFT(info, 12) END),
ADD KEY (ip_info);
严格来说,这仍然是每一行的索引,但至少它不会将您的任何值存储在索引中,除非操作是 'ip'。
P.S.: 我没有测试过上面的例子,如果有语法错误,请见谅。