MySQL: Créer un index s'il n'existe pas

62

Est-il possible de créer un index dans MySQL s'il n'existe pas?

MySQL ne supporte pas le format évident:

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

La version de MySQL ( mysql -V) est 5.1.48, mais je pense que MySQL n’a pas les CREATE INDEX IF NOT EXISTcapacités requises dans toutes ses versions.

Quel est le bon moyen de créer un index uniquement s'il n'existe pas déjà dans MySQL?

Adam Matan
la source

Réponses:

36

Cette fonctionnalité n'existe pas. Il y a deux choses à garder à l'esprit:

Créez quand même l'index

Vous pouvez générer un index de manière à ce qu'il soit créé sans vérifier si l'index existe à l'avance. Par exemple, vous pouvez exécuter ce qui suit:

ALTER TABLE table_name ADD INDEX (column_to_index);
ALTER TABLE table_name ADD INDEX (column_to_index);

Cela va certainement créer deux index sans vérification. Un nom sera attribué à chaque index (peut-être column_to_index, column_to_index_1). Bien sûr, vous essayez d'éviter cela.

Vérifiez d'abord INFORMATION_SCHEMA

Voici la mise en page de 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>

Vous pouvez simplement demander l'existence de l'index par son nom. Par exemple, avant de courir

CREATE INDEX index_name ON mytable(column);

Vous devez courir

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

Si IndexIsIl est 0, vous pouvez créer dans l'index. Peut-être que vous pouvez écrire une procédure stockée pour créer un index sur la table de votre choix.

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 ;

Voici un exemple d'analyse (Hey Remember This Table? Il est tiré de la question que vous avez posée le 27 juin 2012 ):

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>

Essaie !!!

RolandoMySQLDBA
la source
37

J'ai quelque chose de similaire avec using SELECT IF()statement dans MySQL si vous essayez de ne pas avoir de procédures:

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;

Ici le select ifa ce format if (condition, true_case, false_case). Le select 'index index_1 exists'est un cas factice. et _____joue le rôle de pseudonyme. Si aucun alias n'est créé, le nom de la colonne et la ligne sont tous deux affichés index index_1 exists, ce qui crée encore plus de confusion. pour être plus descriptif, vous pouvez utiliser 'select ''index index_1 exists'' as _______;'.

Mithun B
la source
3

Si vous nommez l'index, la requête échouera si l'index existe déjà (testé dans MySQL 8.0):

ALTER TABLE `my_table` ADD INDEX `col_idx` (`col` DESC);

Code d'erreur: 1061. Nom de clé en double 'col_idx';

Donc, vous pouvez juste attraper l'exception et l'ignorer, par exemple en 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
    }
}
les noisettes
la source
2
SELECT COUNT(*)
FROM information_schema.statistics
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME = 'table_name' 
  AND INDEX_NAME = 'index_name'; 

Ma requête vous donnerait le nombre d'index présents sur une table avec un nom d'index particulier. En fonction de ce nombre, vous pouvez décider d’émettre CREATE INDEXou non une commande.

Testé sur MySQL version 5.5 .

MariaDB supporte la IF NOT EXISTSsyntaxe . Vous pouvez utiliser CREATE INDEX IF NOT EXISTSlà-bas.

Bennet Joseph
la source