それが存在しない場合、MySQLでインデックスを作成する方法はありますか?
MySQLは明白なフォーマットをサポートしていません:
CREATE INDEX IF NOT EXISTS index_name ON table(column)
ERROR 1064 (42000): You have an error in your SQL syntax;...
MySQLのバージョン(mysql -V
)は5.1.48ですが、MySQLはすべてのバージョンでCREATE INDEX IF NOT EXIST
機能を欠いていると思います。
MySQLにまだ存在しない場合にのみ、インデックスを作成する正しい方法は何ですか?
その機能は存在しません。次の2つの点に注意してください。
事前にインデックスが存在することを確認せずにインデックスを作成する方法で、インデックスを生成できます。たとえば、次のコマンドを実行できます。
ALTER TABLE table_name ADD INDEX (column_to_index);
ALTER TABLE table_name ADD INDEX (column_to_index);
これは間違いなくチェックなしで2つのインデックスを作成します。各インデックスには名前が割り当てられます(おそらくcolumn_to_index、column_to_index_1)。もちろん、あなたはそれを避けようとしています。
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>
名前でインデックスの存在を照会するだけです。たとえば、実行する前に
CREATE INDEX index_name ON mytable(column);
走る必要がある
SELECT COUNT(1) IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_schema=DATABASE() AND table_name='mytable' AND index_name='index_name';
IndexIsThereが0の場合、インデックスに作成できます。おそらく、選択したテーブルにインデックスを作成するストアドプロシージャを作成できます。
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 ;
以下は実行例です(この表を覚えていますか?それは 2012年6月27日にあなたが尋ねた質問)からのものです ):
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>
試してみる !!!
MySQLでSELECT IF()
ステートメントを使用した場合と同様の手順があります。
_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;
_
ここでは、_select if
_の形式はif (condition, true_case, false_case)
です。 _select 'index index_1 exists'
_はダミーのケースです。および______
_はエイリアス名の役割を果たします。エイリアスが行われていない場合、列名と行の両方に_index index_1 exists
_が表示され、さらに混乱します。よりわかりやすくするには、_'select ''index index_1 exists'' as _______;'
_を使用できます。
インデックスに名前を付けた場合、インデックスがすでに存在しているとクエリは失敗します(MySQL 8.0でテスト済み)。
ALTER TABLE `my_table` ADD INDEX `col_idx` (`col` DESC);
エラーコード:1061。重複したキー名 'col_idx';
したがって、たとえば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
}
}
SELECT COUNT(*)
FROM information_schema.statistics
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'table_name'
AND INDEX_NAME = 'index_name';
私のクエリは、特定のindex_nameを持つテーブルに存在するインデックスの数を提供します。そのカウントに基づいて、CREATE INDEX
コマンドを発行するかどうかを決定できます。
MariaDBは IF NOT EXISTS
構文 をサポートしています。そこでCREATE INDEX IF NOT EXISTS
を使用できます。