MySQL:如果不存在则创建索引

Ada*_*tan 80 mysql index if-not-exists

如果不存在,有没有办法在 MySQL 中创建索引?

MySQL 不支持明显的格式:

CREATE INDEX IF NOT EXISTS index_name ON table(column)
ERROR 1064 (42000): You have an error in your SQL syntax;...
Run Code Online (Sandbox Code Playgroud)

MySQL 版本( mysql -V) 是5.1.48,但我认为MySQL 缺乏CREATE INDEX IF NOT EXIST所有版本的能力。

仅当 MySQL 中不存在索引时,创建索引的正确方法是什么?

Rol*_*DBA 58

该功能不存在。有两件事要记住:

无论如何创建索引

您可以以创建索引的方式生成索引,而无需提前检查索引是否存在。例如,您可以运行以下命令:

ALTER TABLE table_name ADD INDEX (column_to_index);
ALTER TABLE table_name ADD INDEX (column_to_index);
Run Code Online (Sandbox Code Playgroud)

这肯定会在不检查的情况下创建两个索引。每个索引都将被分配一个名称(可能是 column_to_index、column_to_index_1)。当然,您正在努力避免这种情况。

首先检查 INFORMATION_SCHEMA

这是 INFORMATION_SCHEMA.STATISTICS 的布局:

mysql> show create table statistics\G
*************************** 1. row ***************************
       Table: STATISTICS
Create Table: CREATE TEMPORARY TABLE `STATISTICS` (
  `TABLE_CATALOG` varchar(512) NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) NOT NULL DEFAULT '',
  `TABLE_NAME` varchar(64) NOT NULL DEFAULT '',
  `NON_UNIQUE` bigint(1) NOT NULL DEFAULT '0',
  `INDEX_SCHEMA` varchar(64) NOT NULL DEFAULT '',
  `INDEX_NAME` varchar(64) NOT NULL DEFAULT '',
  `SEQ_IN_INDEX` bigint(2) NOT NULL DEFAULT '0',
  `COLUMN_NAME` varchar(64) NOT NULL DEFAULT '',
  `COLLATION` varchar(1) DEFAULT NULL,
  `CARDINALITY` bigint(21) DEFAULT NULL,
  `SUB_PART` bigint(3) DEFAULT NULL,
  `PACKED` varchar(10) DEFAULT NULL,
  `NULLABLE` varchar(3) NOT NULL DEFAULT '',
  `INDEX_TYPE` varchar(16) NOT NULL DEFAULT '',
  `COMMENT` varchar(16) DEFAULT NULL,
  `INDEX_COMMENT` varchar(1024) NOT NULL DEFAULT ''
) ENGINE=MEMORY DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

您可以按名称查询索引是否存在。例如,在您运行之前

CREATE INDEX index_name ON mytable(column);
Run Code Online (Sandbox Code Playgroud)

你需要跑

SELECT COUNT(1) IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_schema=DATABASE() AND table_name='mytable' AND index_name='index_name';
Run Code Online (Sandbox Code Playgroud)

如果IndexIs为0,则可以在索引中创建。也许您可以编写一个存储过程来在您选择的表上创建索引。

DELIMITER $$

DROP PROCEDURE IF EXISTS `adam_matan`.`CreateIndex` $$
CREATE PROCEDURE `adam_matan`.`CreateIndex`
(
    given_database VARCHAR(64),
    given_table    VARCHAR(64),
    given_index    VARCHAR(64),
    given_columns  VARCHAR(64)
)
BEGIN

    DECLARE IndexIsThere INTEGER;

    SELECT COUNT(1) INTO IndexIsThere
    FROM INFORMATION_SCHEMA.STATISTICS
    WHERE table_schema = given_database
    AND   table_name   = given_table
    AND   index_name   = given_index;

    IF IndexIsThere = 0 THEN
        SET @sqlstmt = CONCAT('CREATE INDEX ',given_index,' ON ',
        given_database,'.',given_table,' (',given_columns,')');
        PREPARE st FROM @sqlstmt;
        EXECUTE st;
        DEALLOCATE PREPARE st;
    ELSE
        SELECT CONCAT('Index ',given_index,' already exists on Table ',
        given_database,'.',given_table) CreateindexErrorMessage;   
    END IF;

END $$

DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

这是一个示例运行(嘿还记得这张表吗?它来自您在 2012 年 6 月 27 日提出的问题):

mysql> show create table pixels\G
*************************** 1. row ***************************
       Table: pixels
Create Table: CREATE TABLE `pixels` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `type` varchar(30) DEFAULT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `pixel_data` blob,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> call createindex('adam_matan','pixels','type_timestamp_id_ndx','type,timestamp,id');
Query OK, 0 rows affected (0.20 sec)

mysql> show create table pixels\G
*************************** 1. row ***************************
       Table: pixels
Create Table: CREATE TABLE `pixels` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `type` varchar(30) DEFAULT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `pixel_data` blob,
  PRIMARY KEY (`id`),
  KEY `type_timestamp_id_ndx` (`type`,`timestamp`,`id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> call createindex('adam_matan','pixels','type_timestamp_id_ndx','type,timestamp,id');
+-----------------------------------------------------------------------+
| CreateindexErrorMessage                                               |
+-----------------------------------------------------------------------+
| Index type_timestamp_id_ndx Already Exists on Table adam_matan.pixels |
+-----------------------------------------------------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

试一试 !!!

  • 已经 7 年了,我不敢相信没有人评论过你从一个老问题 OP 中拉出一张桌子。这就是天才的一击,我想 OP 可以从他们自己的代码中看到它学到更多。唉,他们似乎再也没有回来,他们的损失是我的收获。感谢分享这个:) (3认同)

Mit*_*n B 44

SELECT IF()如果您尝试不使用过程,我会与MySQL 中的using语句类似:

select if (
    exists(
        select distinct index_name from information_schema.statistics 
        where table_schema = 'schema_db_name' 
        and table_name = 'tab_name' and index_name like 'index_1'
    )
    ,'select ''index index_1 exists'' _______;'
    ,'create index index_1 on tab_name(column_name_names)') into @a;
PREPARE stmt1 FROM @a;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
Run Code Online (Sandbox Code Playgroud)

这里select if有这种格式if (condition, true_case, false_case)。这select 'index index_1 exists'是一个假案。并_____起到别名的作用。如果别名未完成,则列名和行都显示index index_1 exists,这会更加混乱。为了更具描述性,您可以使用'select ''index index_1 exists'' as _______;'.


小智 7

SELECT COUNT(*)
FROM information_schema.statistics
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME = 'table_name' 
  AND INDEX_NAME = 'index_name'; 
Run Code Online (Sandbox Code Playgroud)

我的查询将为您提供具有特定 index_name 的表上存在的索引计数。根据该计数,您可以决定是否发出CREATE INDEX命令。

在 MySQL 5.5 版上测试

MariaDB 支持IF NOT EXISTS语法。你可以CREATE INDEX IF NOT EXISTS在那里使用。


the*_*uts 6

如果您命名索引,如果索引已经存在(在 MySQL 8.0 中测试),则查询将失败:

ALTER TABLE `my_table` ADD INDEX `col_idx` (`col` DESC);
Run Code Online (Sandbox Code Playgroud)

错误代码:1061。重复的键名“col_idx”;

因此,您可以捕获异常并忽略它,例如在 PHP 中:

try {
    $db->query('ALTER TABLE `my_table` ADD INDEX `col_idx` (`col` DESC) VISIBLE;');
} catch (PDOException $ex) {
    if($exception->errorInfo[2] == 1061) {
        // Index already exists
    } else {
        // Another error occurred
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这似乎比公认的答案更直接。 (2认同)
  • @BradRhoads 确实如此,但它需要使用一些脚本或编程语言。如果创建索引是通过数据库控制台运行的 SQL 脚本的一部分,那么这不是一个选项。 (2认同)