71

我记得在 Oracle 中可以基于函数进行索引,例如SUBSTRING(id,1,8).

MySQL 支持这个吗?如果没有,有没有其他选择?

4

4 回答 4

60

不,不是一般意义上的,我什至不相信 5.6(首次编写此答案时的最新版本)具有此功能。值得注意的是,8.0.13 及以上版本现在支持功能索引,让您无需下文介绍的触发方法即可实现您所需要的。

如果您运行的是旧版本的mysql可以仅使用列的前导部分(此功能已存在很长时间),但不能从第二个或后续字符开始,或任何其他更复杂的功能.

例如,以下使用名称的前五个字符创建索引:

create index name_first_five on cust_table (name(5));

对于更复杂的表达式,您可以通过在其中包含可索引数据的另一列来实现类似的效果,然后使用插入/更新触发器来确保正确填充它。

除了为冗余数据浪费空间之外,这几乎是一回事。

而且,虽然它在技术上违反了 3NF,但通过使用触发器来保持数据同步可以缓解这种情况(这是为了提高性能而经常做的事情)。

于 2012-05-15T06:15:21.597 回答
47

MySQL 自8.0.13起支持此功能

https://dev.mysql.com/doc/refman/8.0/en/create-index.html#create-index-functional-key-parts

MySQL 8.0.13 和更高版本支持索引表达式值而不是列或列前缀值的功能键部分。使用功能键部分可以对未直接存储在表中的值进行索引。例子:

CREATE TABLE t1 (col1 INT, col2 INT, INDEX func_index ((ABS(col1))));
CREATE INDEX idx1 ON t1 ((col1 + col2));
CREATE INDEX idx2 ON t1 ((col1 + col2), (col1 - col2), col1);
ALTER TABLE t1 ADD INDEX ((col1 * 40) DESC);

具有多个关键部分的索引可以混合非功能性和功能性关键部分。

对于 8.0.13 之前的版本,有以下替代方案:

1. MySQL 5.7.6 起

您可以使用自动生成的列来保存带有索引的子字符串:

CREATE TABLE SomeTable (
    id CHAR(10),
    sub_id CHAR(8) AS SUBSTRING(id, 1, 8) STORED, INDEX(sub_id)
)

正如Benjamin所指出的,InnoDB 支持虚拟列上的二级索引,因此可以省略 STORED 关键字。事实上,虚拟列上的二级索引可能更可取。更多信息在这里:二级索引和生成的列

2. MySQL 5.7.6之前

您可以使用由触发器更新的列及其索引:

CREATE TABLE SomeTable (
    id CHAR(10),
    sub_id CHAR(8) , INDEX(sub_id)
);

CREATE TRIGGER TR_SomeTable_INSERT_sub_id
    BEFORE INSERT
    ON SomeTable FOR EACH ROW 
    SET NEW.sub_id = SUBSTRING(NEW.id, 1, 8);

CREATE TRIGGER TR_SomeTable_UPDATE_sub_id
    BEFORE UPDATE
    ON SomeTable FOR EACH ROW 
    SET NEW.sub_id = SUBSTRING(NEW.id, 1, 8);
于 2016-02-13T14:13:32.150 回答
18

从 MySQL 5.7.5 开始,这可以使用新的Generated Columns

于 2015-11-10T00:01:41.183 回答
3

是的,我们可以在 MySQL 中创建功能索引。此功能可从 MySQL 8.0.13 获得。(其他 RDBMS 在其早期版本中具有此功能,但 MySQL 在其版本 8.0.13 中引入了它)。功能指标

这里我给出了一个在 MySQL8.0 中创建函数索引的例子

这是查询

SELECT * FROM app_user WHERE month(createdOn) = 5;

mysql> SELECT * FROM app_user WHERE month(createdOn) = 5;
7e9e2b7bc2e9bde15504f6c5658458ab - 74322 rows in set (5.01 sec)

即使我在 createdOn 列上有索引,它也会执行超过 5 秒以获取 74322 条记录。(优化器不使用 createdOn 列上的索引,因为它被 month() 函数屏蔽)

现在,我使用以下语法在列上创建了一个功能索引。

mysql> ALTER TABLE app_user ADD INDEX
         idx_month_createdon((month(createdOn)));
Query OK, 0 rows affected (1 min 17.37 sec) Records: 0 Duplicates: 0
Warnings: 0

mysql> SELECT * FROM app_user WHERE month(createdOn) = 5;
7e9e2b7bc2e9bde15504f6c5658458ab - 74322 rows in set (0.29 sec)

创建功能索引后,它在 0.29 秒内执行。

在Mysql网站上很难找到功能索引文档,以功能关键部件的名义

而且我们不能删除具有功能索引的列。为此,我们需要首先删除功能索引。

mysql> ALTER TABLE app_user DROP COLUMN createdOn;
Cannot drop column 'createdOn' because it is used by a functional
index. In order to drop the column, you must remove the functional
index.

如果您使用 MySQL > 5.7.5,则可以使用生成的列来实现相同的目的。

于 2019-07-20T05:59:45.397 回答