web-dev-qa-db-fra.com

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

Existe-t-il un moyen de créer un index dans MySQL s'il n'existe pas?

MySQL ne prend pas en charge le format évident:

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

Version MySQL (mysql -V) est 5.1.48, mais je pense que MySQL n'a pas le CREATE INDEX IF NOT EXIST capacité dans toutes ses versions.

Quelle est la bonne façon de créer un index uniquement s'il n'existe pas déjà dans MySQL?

67
Adam Matan

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 telle manière que l'index soit créé sans le vérifier, 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. Chaque index se verra attribuer un nom (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 disposition 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 rechercher l'existence de l'index par nom. Par exemple, avant d'exécuter

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 IndexIsThere est 0, vous pouvez créer dans l'index. Vous pouvez peut-être é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'exécution (Hé, souviens-toi de ce tableau? C'est de la question que tu as 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 !!!

40
RolandoMySQLDBA

J'ai quelque chose de similaire avec l'utilisation de l'instruction SELECT IF() 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 if A ce format if (condition, true_case, false_case). Le select 'index index_1 exists' Est un boîtier factice. et _____ joue le rôle de nom d'alias. Si l'alias n'est pas fait, le nom de la colonne et la ligne affichent tous les deux index index_1 exists, Ce qui est encore plus déroutant. pour être plus descriptif, vous pouvez utiliser 'select ''index index_1 exists'' as _______;'.

39
Mithun B

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';

Vous pouvez donc simplement intercepter 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
    }
}
6
the_nuts
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_index particulier. En fonction de ce nombre, vous pouvez décider d'émettre un CREATE INDEX commande ou non.

Testé sur MySQL version 5.5 .

MariaDB prend en charge IF NOT EXISTS syntaxe . Vous pouvez utiliser CREATE INDEX IF NOT EXISTS Là.

4
Bennet Joseph