MySQL: Buat indeks Jika tidak ada

62

Apakah ada cara untuk membuat indeks di MySQL jika tidak ada?

MySQL tidak mendukung format yang jelas:

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

Versi MySQL ( mysql -V) adalah 5.1.48, tapi saya pikir MySQL tidak memiliki CREATE INDEX IF NOT EXISTkemampuan di semua versinya.

Apa cara yang benar untuk membuat indeks hanya jika belum ada di MySQL?

Adam Matan
sumber

Jawaban:

36

Fungsi itu tidak ada. Ada dua hal yang perlu diingat:

Buat Indeks Pokoknya

Anda dapat menghasilkan indeks sedemikian rupa sehingga indeks dibuat tanpa memeriksa indeks yang ada sebelumnya. Misalnya, Anda dapat menjalankan yang berikut ini:

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

Ini pasti akan membuat dua indeks tanpa memeriksa. Setiap indeks akan diberi nama (mungkin column_to_index, column_to_index_1). Tentu saja, Anda berusaha menghindarinya.

Periksa INFORMATION_SCHEMA terlebih dahulu

Berikut adalah tata letak 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>

Anda bisa menanyakan keberadaan indeks dengan nama. Misalnya, sebelum Anda menjalankan

CREATE INDEX index_name ON mytable(column);

Anda harus berlari

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

Jika IndexIsThere adalah 0, Anda dapat membuat dalam indeks. Mungkin Anda bisa menulis prosedur tersimpan untuk membuat indeks di atas meja pilihan Anda.

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 ;

Ini adalah contoh uji coba (Hey Remember This Table? Ini dari pertanyaan yang Anda tanyakan pada 27 Juni 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>

Cobalah !!!

RolandoMySQLDBA
sumber
37

Saya memiliki sesuatu yang mirip dengan menggunakan SELECT IF()pernyataan di MySQL jika Anda mencoba untuk tidak memiliki prosedur:

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;

Di sini select ifmemiliki format ini if (condition, true_case, false_case). Ini select 'index index_1 exists'adalah kasus boneka. dan _____memainkan peran nama alias. Jika alias tidak dilakukan maka nama kolom dan baris keduanya ditampilkan index index_1 exists, yang lebih membingungkan. agar lebih deskriptif bisa Anda gunakan 'select ''index index_1 exists'' as _______;'.

Mithun B
sumber
3

Jika Anda memberi nama indeks, kueri akan gagal jika indeks sudah ada (diuji di MySQL 8.0):

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

Kode Kesalahan: 1061. Nama kunci duplikat 'col_idx';

Jadi Anda bisa menangkap pengecualian dan mengabaikannya, misalnya dalam 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
    }
}
kacang
sumber
2
SELECT COUNT(*)
FROM information_schema.statistics
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME = 'table_name' 
  AND INDEX_NAME = 'index_name'; 

Kueri saya akan memberi Anda jumlah indeks yang ada pada tabel dengan nama index tertentu. Berdasarkan hitungan itu, Anda dapat memutuskan apakah akan mengeluarkan CREATE INDEXperintah atau tidak.

Diuji pada MySQL versi 5.5 .

MariaDB mendukung IF NOT EXISTSsintaks . Anda bisa menggunakannya di CREATE INDEX IF NOT EXISTSsana.

Bennet Joseph
sumber