MySQL: Index erstellen Wenn nicht vorhanden

62

Gibt es eine Möglichkeit, einen Index in MySQL zu erstellen, wenn er nicht existiert?

MySQL unterstützt nicht das offensichtliche Format:

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

MySQL version ( mysql -V) ist 5.1.48, aber ich denke, dass MySQL CREATE INDEX IF NOT EXISTin all seinen Versionen nicht die Fähigkeit besitzt.

Was ist der richtige Weg, um einen Index nur dann zu erstellen, wenn er noch nicht in MySQL existiert?

Adam Matan
quelle

Antworten:

36

Diese Funktionalität existiert nicht. Es gibt zwei Dinge zu beachten:

Erstelle trotzdem den Index

Sie können den Index so generieren, dass er erstellt wird, ohne vorher zu überprüfen, ob der Index vorhanden ist. Beispielsweise können Sie Folgendes ausführen:

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

Dadurch werden definitiv zwei Indizes erstellt, ohne dass dies überprüft wird. Jedem Index wird ein Name zugewiesen (möglicherweise column_to_index, column_to_index_1). Natürlich versuchen Sie das zu vermeiden.

Überprüfen Sie zuerst INFORMATION_SCHEMA

Hier ist das Layout von 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>

Sie können nur die Existenz des Index nach Namen abfragen. Zum Beispiel, bevor Sie rennen

CREATE INDEX index_name ON mytable(column);

Du musst rennen

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

Wenn IndexIsThere 0 ist, können Sie im Index erstellen. Vielleicht können Sie eine gespeicherte Prozedur schreiben, um einen Index für die Tabelle Ihrer Wahl zu erstellen.

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 ;

Hier ist ein Probelauf (Hey, erinnerst du dich an diese Tabelle? Er stammt von der Frage, die du am 27. Juni 2012 gestellt hast ):

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>

Versuche es !!!

RolandoMySQLDBA
quelle
37

Ich habe etwas Ähnliches mit using- SELECT IF()Anweisung in MySQL, wenn Sie versuchen, keine Prozeduren zu haben:

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;

Hier select ifhat der dieses Format if (condition, true_case, false_case). Das select 'index index_1 exists'ist ein Dummy-Fall. und _____spielt die Rolle des Aliasnamens. Wenn kein Alias ​​erstellt wird, werden sowohl der Spaltenname als auch die Zeile angezeigt index index_1 exists, was noch mehr Verwirrung stiftet. um beschreibender zu sein, können Sie verwenden 'select ''index index_1 exists'' as _______;'.

Mithun B
quelle
3

Wenn Sie den Index benennen, schlägt die Abfrage fehl, wenn der Index bereits vorhanden ist (getestet in MySQL 8.0):

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

Fehlercode: 1061. Doppelter Schlüsselname 'col_idx';

Sie können die Ausnahme also einfach abfangen und ignorieren, zum Beispiel in 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
    }
}
die Nüsse
quelle
2
SELECT COUNT(*)
FROM information_schema.statistics
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME = 'table_name' 
  AND INDEX_NAME = 'index_name'; 

Meine Abfrage gibt die Anzahl der Indizes an, die in einer Tabelle mit einem bestimmten Indexnamen vorhanden sind. Anhand dieser Anzahl können Sie entscheiden, ob Sie einen CREATE INDEXBefehl ausgeben möchten oder nicht.

Getestet unter MySQL Version 5.5 .

MariaDB unterstützt die IF NOT EXISTSSyntax . Sie können CREATE INDEX IF NOT EXISTSdort verwenden.

Bennet Joseph
quelle