在创建之前确定MySQL表索引是否存在

时间:2010-09-02 11:28:08

标签: mysql stored-procedures indexing

我们系统的自动数据库迁移过程涉及运行包含新表定义及其附带索引的.sql脚本。

我要求只有在它们不存在的情况下才能创建这些表和索引。通过使用IF NOT EXISTS来处理表,但在创建索引时不存在这样的语法。

我已经尝试编写一个存储过程,如下所示,但这可能因为你无法从show语句中选择而失败。

DELIMITER $$
DROP PROCEDURE IF EXISTS csi_add_index $$
CREATE PROCEDURE csi_add_index(in theTable varchar(128), in theIndexName varchar(128), in theIndexColumns varchar(128)  )
BEGIN
 IF(((SELECT COUNT(*) FROM (SHOW KEYS FROM theTable WHERE key_name = theIndexName)) tableInfo = 0) THEN
   SET @s = CONCAT('CREATE INDEX ' , theIndexName , ' ON ' , theTable, '(', theIndexColumns, ')');
   PREPARE stmt FROM @s;
   EXECUTE stmt;
 END IF;
END $$

我已经考虑过删除和重新创建但是过程(因为它存在)假设它不会遇到任何错误因此我想首先检查是否存在。

是否有其他方法可以检索表的索引以检查在创建之前索引是否已存在,或者是否有人建议更好的方法来管理它?

编辑:请注意,这是一个自动程序,无人为干预。

7 个答案:

答案 0 :(得分:12)

SELECT INDEX_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE
`TABLE_CATALOG` = 'def' AND `TABLE_SCHEMA` = DATABASE() AND
`TABLE_NAME` = theTable AND `INDEX_NAME` = theIndexName

答案 1 :(得分:8)

在我的头撞墙和激烈的谷歌搜索后,我找到了information_schema.statistics桌子。它包含表的index_name。

我的存储过程现在是

DELIMITER $$

DROP PROCEDURE IF EXISTS csi_add_index $$
CREATE PROCEDURE csi_add_index(in theTable varchar(128), in theIndexName varchar(128), in theIndexColumns varchar(128)  )
BEGIN
 IF((SELECT COUNT(*) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name =
theTable AND index_name = theIndexName)  = 0) THEN
   SET @s = CONCAT('CREATE INDEX ' , theIndexName , ' ON ' , theTable, '(', theIndexColumns, ')');
   PREPARE stmt FROM @s;
   EXECUTE stmt;
 END IF;
END $$

并按预期工作。

感谢您的建议。

答案 2 :(得分:1)

使用SHOW INDEX FROM mytable FROM mydb;并检查索引是否存在 - 每个返回的行代表索引的一部分;您可能最感兴趣的列是Key_name,因为它包含索引的名称。 Documentation here

答案 3 :(得分:1)

您可以查询infomration_schema数据库以获取此信息以及更多有用的信息

http://dev.mysql.com/doc/refman/5.0/en/information-schema.html

答案 4 :(得分:0)

您可以使用正确的索引创建另一个表,复制旧表中的所有内容然后将其删除,并将新表重命名为旧表。有点hackish,可能对大表有点沉重,但仍然相当简单。

答案 5 :(得分:0)

不是新版本,而是包含调用创建2个索引的更完整的解决方案。

USE MyDatabaseName;
DELIMITER $$
-- Create a temporary stored procedure for checking if Indexes exist before attempting to re-create them.
DROP PROCEDURE IF EXISTS `MyDatabaseName`.`spCreateIndex` $$
CREATE PROCEDURE `MyDatabaseName`.`spCreateIndex` (tableName VARCHAR(128), in indexName VARCHAR(128), in indexColumns VARCHAR(128))
BEGIN
  IF((SELECT COUNT(*) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() AND table_name = tableName AND index_name = indexName)  = 0) THEN
    SET @sqlCommand = CONCAT('CREATE INDEX ' , indexName , ' ON ' , tableName, '(', indexColumns, ')');
    PREPARE _preparedStatement FROM @sqlCommand;
    EXECUTE _preparedStatement;
  END IF;
END $$
DELIMITER ;

-- Create the Indexes if they do not exist already.
CALL spCreateIndex('MyCustomers', 'idxCustNum', 'CustomerNumber');
CALL spCreateIndex('MyProducts', 'idxProductName', 'ProductName');

DELIMITER $$
-- Drop the temporary stored procedure.
DROP PROCEDURE IF EXISTS `MyDatabaseName`.`spCreateIndex` $$
DELIMITER ;

答案 6 :(得分:0)

由于Text和Blob需要大小,因此我将其添加到存储过程中。

DROP PROCEDURE IF EXISTS createIndex;

DELIMITER $$
-- Create a temporary stored procedure for checking if Indexes exist before attempting to re-create them. => can be called
$$
CREATE PROCEDURE `createIndex`(
    IN `tableName` VARCHAR(128),
    IN `indexName` VARCHAR(128),
    IN `indexColumns` VARCHAR(128),
    IN `indexSize` VARCHAR(128)
)
BEGIN
  IF((SELECT COUNT(*) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() AND table_name = tableName AND index_name = indexName)  = 0) THEN
        IF(indexSize > 0) THEN
            SET @sqlCommand = CONCAT('CREATE INDEX ' , indexName , ' ON ' , tableName, '(', indexColumns, '(' , indexSize, '))');
        ELSE
            SET @sqlCommand = CONCAT('CREATE INDEX ' , indexName , ' ON ' , tableName, '(', indexColumns, ')');
        END IF;
    PREPARE _preparedStatement FROM @sqlCommand;
    EXECUTE _preparedStatement;
  END IF;
END $$
DELIMITER ;