MySQL : 존재하지 않는 경우 인덱스 생성


62

인덱스가 존재하지 않는 경우 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에 인덱스가없는 경우에만 인덱스를 생성하는 올바른 방법은 무엇입니까?

답변:


36

해당 기능이 없습니다. 명심해야 할 두 가지가 있습니다.

어쨌든 인덱스 만들기

색인이 미리 존재하는지 확인하지 않고 색인이 작성되는 방식으로 색인을 생성 할 수 있습니다. 예를 들어 다음을 실행할 수 있습니다.

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

이것은 확인하지 않고 두 개의 인덱스를 생성합니다. 각 인덱스에는 이름이 할당됩니다 (아마 column_to_index, column_to_index_1). 물론, 당신은 그것을 피하려고 노력하고 있습니다.

INFORMATION_SCHEMA를 먼저 확인하십시오.

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>

시도 해봐 !!!


37

SELECT IF()절차를 따르지 않으려는 경우 MySQL에서 명령문 을 사용하는 것과 비슷한 것이 있습니다.

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


3

인덱스 이름을 지정하면 인덱스가 이미 존재하면 쿼리가 실패합니다 (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
    }
}

2
SELECT COUNT(*)
FROM information_schema.statistics
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME = 'table_name' 
  AND INDEX_NAME = 'index_name'; 

내 쿼리는 특정 index_name을 가진 테이블에 존재하는 인덱스 수를 제공합니다. 이 수에 따라 CREATE INDEX명령 을 발행할지 여부를 결정할 수 있습니다 .

MySQL 버전 5.5에서 테스트되었습니다 .

MariaDB는 IF NOT EXISTS구문을 지원 합니다 . CREATE INDEX IF NOT EXISTS거기서 사용할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.