web-dev-qa-db-fra.com

Comment utiliser "s'il existe" pour créer ou supprimer un index dans MySQL?

Je me demandais s'il existait un moyen de vérifier l'existence d'un index avant de le créer ou de le détruire sur MySQL. Il semble qu'il y ait eu une demande de fonctionnalité il y a quelques années, mais je ne trouve pas de documentation pour une solution. Cela doit être fait dans une application PHP utilisant MDB2.

49
Paul

Voici mes 4 doublures:

set @exist := (select count(*) from information_schema.statistics where table_name = 'table' and index_name = 'index' and table_schema = database());
set @sqlstmt := if( @exist > 0, 'select ''INFO: Index already exists.''', 'create index i_index on tablename ( columnname )');
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
41
Nikhil S

Le modificateur IF EXISTS n'est pas encore construit pour DROP INDEX et CREATE INDEX. Mais vous pouvez vérifier manuellement l'existence avant de créer/supprimer un index.

Utilisez cette phrase pour vérifier si l'index existe déjà.

SHOW INDEX FROM table_name WHERE KEY_NAME = 'index_name'
  • Si la requête renvoie zéro (0), alors l'index n'existe pas, vous pouvez le créer.
  • Si la requête renvoie un nombre positif alors que l'index existe, vous pouvez le supprimer.
23
Pablo Venturino

Voici une procédure DROP INDEX IF EXISTS:

DELIMITER $$

DROP PROCEDURE IF EXISTS drop_index_if_exists $$
CREATE PROCEDURE drop_index_if_exists(in theTable varchar(128), in theIndexName 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('DROP INDEX ' , theIndexName , ' ON ' , theTable);
   PREPARE stmt FROM @s;
   EXECUTE stmt;
 END IF;
END $$

DELIMITER ;

Ce code a été créé sur la base de la procédure décrite ici: Déterminer si un index de table MySQL existe avant de créer

11
Datageek

J'ai peaufiné les réponses trouvées ici et où trouver les sprocs suivants pour supprimer et créer des index. Notez que le sproc AddTableIndex peut supprimer l’index si besoin est. Ils acceptent également un nom de schéma qui était essentiel pour mes utilisations.

DELIMITER //

DROP PROCEDURE IF EXISTS migrate.DropTableIndex //

CREATE PROCEDURE migrate.DropTableIndex
    (
        in schemaName varchar(128) -- If null use name of current schema;
        , in tableName varchar(128) -- If null an exception will be thrown.
        , in indexName varchar(128) -- If null an exception will be thrown.
    )
BEGIN
    SET schemaName = coalesce(schemaName, schema());
    IF((SELECT COUNT(*) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = schemaName and table_name = tableName AND index_name = indexName) > 0) THEN
        SET @s = CONCAT('DROP INDEX `' , indexName , '` ON `' , schemaName, '`.`', tableName, '`');
        PREPARE stmt FROM @s;
        EXECUTE stmt;
    END IF;
END //

DROP PROCEDURE IF EXISTS migrate.AddTableIndex//

CREATE PROCEDURE migrate.AddTableIndex
    ( 
        IN schemaName varchar(128) -- If null use name of current schema;
        , IN tableName varchar(128) -- If null an exception will be thrown.
        , IN indexName varchar(128) -- If null an exception will be thrown.
        , IN indexDefinition varchar(1024) -- E.g. '(expireTS_ ASC)'
        , IN ifPresent ENUM('leaveUnchanged', 'dropAndReplace') -- null=leaveUnchanged.
        , OUT outcome tinyint(1) -- 0=unchanged, 1=replaced, 4=added.
    )
    BEGIN

    DECLARE doDrop tinyint(1) DEFAULT NULL;
    DECLARE doAdd tinyint(1) DEFAULT NULL;
    DECLARE tmpSql varchar(4096) DEFAULT '';

    SET schemaName = coalesce(schemaName, schema());
    SET ifPresent = coalesce(ifPresent, 'leaveUnchanged');
    IF EXISTS (SELECT * FROM   INFORMATION_SCHEMA.STATISTICS WHERE  table_schema = schemaName AND table_name = tableName AND index_name = indexName) THEN
        IF (ifPresent = 'leaveUnchanged') THEN
            SET doDrop = 0;
            SET doAdd = 0;
            SET outcome = 0;
            ELSEIF (ifPresent = 'dropAndReplace')
            THEN
            SET doDrop = 1;
            SET doAdd = 1;
            SET outcome = 1;
        END IF;
    ELSE
        SET doDrop = 0;
        SET doAdd = 1;
        SET outcome = 4;
    END IF;

    IF (doDrop = 1) THEN
        SET tmpSql = concat( 'alter table `', schemaName, '`.`', tableName, '` drop index `', indexName, '` ');
        SET @sql = tmpSql;
        PREPARE tmp_stmt FROM @sql;
        EXECUTE tmp_stmt;
        DEALLOCATE PREPARE tmp_stmt;
    END IF;

    IF (doAdd = 1) THEN
        SET tmpSql = concat( 'alter table `', schemaName, '`.`', tableName, '` add index `', indexName, '` (', indexDefinition, ')');
        SET @sql = tmpSql;
        PREPARE tmp_stmt FROM @sql;
        EXECUTE tmp_stmt;
        DEALLOCATE PREPARE tmp_stmt;
    END IF;

    END;
//

DELIMITER ;
2
Thomas Paine

J'ai quelque chose de similaire avec l'utilisation de l'instruction SELECT IF () dans MySQL.

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;

L’avantage d’utiliser if () est qu’il n’a pas besoin de procédures écrites.

1
Mithun B

MySQL Workbench version 6.3 (Mariaq pour fork de MySql)

DROP INDEX IF EXISTS FK_customer__client_school__school_id ON dbname.tablename;
1
SushiGuy

Je pense que cela vous aidera à supprimer votre index existant.

        DELIMITER //
        CREATE PROCEDURE dropIndexing
        ()
        BEGIN

        IF EXISTS(
                    SELECT * FROM information_schema.statistics 
                    WHERE TABLE_SCHEMA = DATABASE() 
                    AND `table_name`='mytable' 
                    AND `index_name` = 'myindex'
                )
        THEN
        ALTER TABLE `mytable` DROP INDEX `myindex`;
        END IF;

        END //
        DELIMITER ;

        CALL dropIndexing();
        DROP PROCEDURE dropIndexing;
0
jeewiya

J'avais des problèmes avec certaines des solutions présentées ici. Voici ce que je suis venu avec:

DELIMITER $$

DROP PROCEDURE IF EXISTS myschema.create_index_if_not_exists $$
CREATE PROCEDURE myschema.create_index_if_not_exists(in p_tableName VARCHAR(128), in p_indexName VARCHAR(128), in p_columnName VARCHAR(128) )
BEGIN

PREPARE stmt FROM 'SELECT @indexCount := COUNT(1) from information_schema.statistics WHERE `table_name` = ? AND `index_name` = ?';
SET @table_name = p_tableName;
SET @index_name = p_indexName;
EXECUTE stmt USING @table_name, @index_name;
DEALLOCATE PREPARE stmt;

-- select @indexCount;

IF( @indexCount = 0 ) THEN
  SELECT 'Creating index';
  SET @createIndexStmt = CONCAT('CREATE INDEX ', p_indexName, ' ON ', p_tableName, ' ( ', p_columnName ,')');
  PREPARE stmt FROM @createIndexStmt;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
END IF;

END $$

DELIMITER ;

Utilisez-le comme suit:

call myschema.create_index_if_not_exists('MyTable','end_time_index','end_time');

Ceci a été testé sur MAC OS X 10.8.2 avec MySQL 5.5.24 et sur Windows 7 avec MySQL 5.5.21

0
Wim Deblauwe

Voici une solution de contournement pour le DROP INDEX IF EXISTS, qui manque dans les versions de MySQL et MariaDB antérieures à v10.1.4. Vous pouvez également l'utiliser pour toutes les autres instructions de votre choix, en fonction de l'existence d'un INDEX (par exemple, pour SELECT "info: index exists." comme dans l'exemple ci-dessous).

-- DROP INDEX IF EXISTS
SELECT
    COUNT(*)
INTO
    @INDEX_my_index_ON_TABLE_my_table_EXISTS
FROM
    `information_schema`.`statistics`
WHERE
    `table_schema` = 'my_database'
    AND `index_name` = 'my_index'
    AND `table_name` = 'my_table'
;
SET @statement := IF(
    @INDEX_my_index_ON_TABLE_my_table_EXISTS > 0,
    -- 'SELECT "info: index exists."',
    'DROP INDEX `my_index` ON `my_table`',
    'SELECT "info: index does not exist."'
);
PREPARE statement FROM @statement;
EXECUTE statement;
0
automatix