【问题标题】:Determining if MySQL table index exists before creating在创建之前确定 MySQL 表索引是否存在
【发布时间】:2011-04-07 07:11:37
【问题描述】:

我们系统的自动数据库迁移过程涉及运行 .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 $$

我考虑过删除并重新创建,但该过程,因为它存在,假设它不会遇到错误,因此我想先检查是否存在。

是否有另一种方法来检索表的索引以在创建之前检查索引是否已经存在,或者任何人都可以提出更好的方法来管理它?

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

【问题讨论】:

    标签: mysql stored-procedures indexing


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 我似乎无法在存储过程的 IF () 语句中使用 SHOW INDEX。如果我知道根据 SELECT 映射到什么,那么我可以使用它,但没有它我无法检查结果。我将编辑问题以澄清这是一个自动化程序,因为可能不清楚。
      【解决方案3】:
      SELECT INDEX_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE
      `TABLE_CATALOG` = 'def' AND `TABLE_SCHEMA` = DATABASE() AND
      `TABLE_NAME` = theTable AND `INDEX_NAME` = theIndexName
      

      【讨论】:

      • 这里的 'TABLE_SCHEMA' = Database() 位很重要,我不知道。意味着如果您在另一个数据库中有同名的表,则不会发生冲突。否则我会得到误报。
      • “table_catalog is null”子句似乎是一个错误。
      • 撰写本文时并非如此——默认目录现在在当前 MySQL 中命名为“def”。
      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        在我的头从墙上敲了几下并进行了激烈的谷歌搜索之后,我找到了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 $$
        

        并按预期工作。

        感谢您的建议。

        【讨论】:

        • 啊,其他人建议这样做。我会给他们接受的答案。谢谢大家。
        【解决方案6】:

        不是新版本,而是更完整的解决方案,包括创建 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 ;
        

        【讨论】:

          【解决方案7】:

          由于 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 ;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-02-02
            • 2011-04-10
            • 2011-11-21
            • 2013-06-02
            • 1970-01-01
            相关资源
            最近更新 更多