변경하려는 InnoDB 테이블이 있습니다. 테이블에는 ~ 80M 개의 행이 있으며 몇 개의 인덱스를 종료합니다.
열 중 하나의 이름을 변경하고 색인을 몇 개 더 추가하고 싶습니다.
- 가장 빠른 방법은 무엇입니까?
- "일반"
alter table
이 가장 빠른 솔루션입니까?
현재 내가 관심있는 것은 속도 :)
sent_at
은 몇 가지 인덱스를 추가하는 것입니다.
변경하려는 InnoDB 테이블이 있습니다. 테이블에는 ~ 80M 개의 행이 있으며 몇 개의 인덱스를 종료합니다.
열 중 하나의 이름을 변경하고 색인을 몇 개 더 추가하고 싶습니다.
alter table
이 가장 빠른 솔루션입니까?현재 내가 관심있는 것은 속도 :)
sent_at
은 몇 가지 인덱스를 추가하는 것입니다.
답변:
ALTER TABLE의 속도를 높이는 한 가지 확실한 방법은 불필요한 인덱스를 제거하는 것입니다
다음은 새 버전의 테이블을로드하는 초기 단계입니다.
CREATE TABLE s_relations_new LIKE s_relations;
#
# Drop Duplicate Indexes
#
ALTER TABLE s_relations_new
DROP INDEX source_persona_index,
DROP INDEX target_persona_index,
DROP INDEX target_persona_relation_type_index
;
다음 사항에 유의하십시오.
source_persona_index는 4 개의 다른 인덱스에서 첫 번째 열이므로 삭제했습니다.
target_persona_index가 다른 두 인덱스의 첫 번째 열이므로 삭제했습니다.
처음 두 열도 target_persona_relation_type_message_id_index에 있기 때문에 target_persona_relation_type_index를 삭제했습니다.
OK 불필요한 인덱스를 처리합니다. 카디널리티가 낮은 인덱스가 있습니까? 이를 결정하는 방법은 다음과 같습니다.
다음 쿼리를 실행하십시오.
SELECT COUNT(DISTINCT sent_at) FROM s_relations;
SELECT COUNT(DISTINCT message_id) FROM s_relations;
SELECT COUNT(DISTINCT target_object_id) FROM s_relations;
귀하의 질문에 따르면 약 80,000,000 개의 행이 있습니다. 일반적으로 MySQL Query Optimizer는 선택한 열의 카디널리티가 테이블 행 수의 5 %보다 큰 경우 인덱스를 사용하지 않습니다. 이 경우 4,000,000이됩니다.
COUNT(DISTINCT sent_at)
> 4,000,000 인
경우ALTER TABLE s_relations_new
DROP INDEX sent_at_index;
COUNT(DISTINCT message_id)
> 4,000,000 인
경우ALTER TABLE s_relations_new
DROP INDEX message_id_index;
COUNT(DISTINCT target_object_id)
> 4,000,000 인
경우ALTER TABLE s_relations_new
DROP INDEX target_object_index;
해당 인덱스의 유용성 또는 사용 불능이 결정되면 데이터를 다시로드 할 수 있습니다
#
# Change the Column Name
# Load the Table
#
ALTER TABLE s_relations_new CHANGE sent_at sent_at_new int(11) DEFAULT NULL;
INSERT INTO s_relations_new SELECT * FROM s_relations;
그게 맞나요? 아니야!
귀하의 웹 사이트가이 기간 동안 가동 된 경우 s_relations_new를로드하는 동안 s_relations에 대해 INSERT가 실행 중일 수 있습니다. 누락 된 행을 어떻게 검색 할 수 있습니까?
s_relations_new에서 최대 ID를 찾아 s_relations에서 해당 ID 뒤에있는 모든 것을 추가하십시오. 테이블이 고정되어이 업데이트에만 사용되도록하려면 s_relation_new에 삽입 된 마지막 행을 가져 오기 위해 약간의 가동 중지 시간이 있어야합니다. 여기 당신이하는 일이 있습니다 :
OS에서 아무도 로그인 할 수 없도록 mysql을 다시 시작하십시오. root @ localhost (TCP / IP 비활성화) :
$ service mysql restart --skip-networking
다음으로 mysql에 로그인하고 마지막 행을로드하십시오.
mysql> SELECT MAX(id) INTO @maxidnew FROM s_relations_new;
mysql> INSERT INTO s_relations_new SELECT * FROM s_relations WHERE id > @maxidnew;
mysql> ALTER TABLE s_relations RENAME s_relations_old;
mysql> ALTER TABLE s_relations_new RENAME s_relations;
그런 다음 mysql을 정상적으로 다시 시작하십시오.
$ service mysql restart
이제 mysql을 중단시킬 수 없다면 s_relations에서 미끼 및 스위치를 수행해야합니다. mysql에 로그인하고 다음을 수행하십시오.
mysql> ALTER TABLE s_relations RENAME s_relations_old;
mysql> SELECT MAX(id) INTO @maxidnew FROM s_relations_new;
mysql> INSERT INTO s_relations_new SELECT * FROM s_relations_old WHERE id > @maxidnew;
mysql> ALTER TABLE s_relations_new RENAME s_relations;
시도 해봐 !!!
주의 사항 :이 작업에 만족하면 최대한 빨리 이전 테이블을 삭제할 수 있습니다.
mysql> DROP TABLE s_relations_old;
정답은 사용중인 MySQL 엔진의 버전에 따라 다릅니다.
5.6+를 사용하는 경우 이름 변경 및 인덱스 추가 / 제거는 온라인 으로 수행 됩니다 (예 : 모든 테이블 데이터를 복사하지 않음).
ALTER TABLE
평소와 같이 사용 하면 이름 바꾸기 및 인덱스 삭제가 즉각적으로 이루어지고 인덱스 추가가 합리적으로 빠릅니다 (모든 테이블을 한 번 읽는 것만 큼 빠름).
5.1 이상을 사용하고 InnoDB 플러그인이 활성화 된 경우 인덱스 추가 / 제거도 온라인 상태가됩니다. 이름 변경에 대해 잘 모르겠습니다.
이전 버전을 사용하는 경우 ALTER TABLE
여전히 가장 빠르지 만 모든 데이터 가 임시 테이블 아래의 임시 테이블에 다시 삽입 되므로 엄청나게 느릴 수 있습니다.
마지막으로, 신화를 해제 할 시간입니다. 불행히도 여기에 답변에 대해 언급 할 카르마가 충분하지 않지만 가장 투표가 많은 답변을 수정하는 것이 중요하다고 생각합니다. 이것은 잘못되었습니다 :
일반적으로 MySQL Query Optimizer는 선택한 열의 카디널리티가 테이블 행 수의 5 %보다 큰 경우 인덱스를 사용하지 않습니다.
실제로 다른 방법 입니다.
인덱스는 적은 행 을 선택하는 데 유용 하므로 높은 카디널리티 를 갖는 것이 중요합니다 . 이는 많은 고유 값과 동일한 값을 가진 통계적으로 적은 행을 의미합니다.
RENAME TABLE
예상대로 인스턴트를 찾았 지만 CHANGE COLUMN
기본 키의 이름을 바꾸는 것이 전체 사본을 수행했습니다 ... 7 시간! 아마도 기본 키이기 때문일까요? 안좋다.
Maria DB 10.1.12와 동일한 문제가 있었지만 설명서를 읽은 후 "사본"작업을 수행하여 테이블 복사본을 제거하는 옵션이 있음을 알았습니다. 이 옵션을 사용하면 alter 테이블이 매우 빠릅니다. 제 경우에는 다음과 같습니다.
alter table user add column (resettoken varchar(256),
resettoken_date date, resettoken_count int), algorithm=inplace;
이것은 매우 빠릅니다. 알고리즘 옵션이 없으면 종료되지 않습니다.
열 이름을 바꾸려면
ALTER TABLE tablename CHANGE columnname newcolumnname datatype;
괜찮고 다운 타임이 없어야합니다.
인덱스의 경우 CREATE INDEX 문은 테이블을 잠급니다. 언급 한대로 사용하지 않은 슬레이브라면 문제가되지 않습니다.
다른 옵션 중 하나는 적절한 열 이름과 인덱스가있는 완전히 새로운 테이블을 만드는 것입니다. 그런 다음 모든 데이터를 복사하고 일련의 데이터를 실행할 수 있습니다.
BEGIN TRAN;
ALTER TABLE RENAME tablename tablenameold;
ALTER TABLE RENAME newtablename tablename;
DROP TABLE tablenameold;
COMMIT TRAN;
이렇게하면 공간을 두 배로 일시적으로 사용하는 비용으로 가동 중지 시간이 최소화됩니다.
나는이 문제도 가지고 있으며이 SQL을 사용했다.
/*on créé la table COPY SANS les nouveaux champs et SANS les FKs */
CREATE TABLE IF NOT EXISTS prestations_copy LIKE prestations;
/* on supprime les FKs de la table actuelle */
ALTER TABLE `prestations`
DROP FOREIGN KEY `fk_prestations_pres_promos`,
DROP FOREIGN KEY `fk_prestations_activites`;
/* on remet les FKs sur la table copy */
ALTER TABLE prestations_copy
ADD CONSTRAINT `fk_prestations_activites` FOREIGN KEY (`act_id`) REFERENCES `activites` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
ADD CONSTRAINT `fk_prestations_pres_promos` FOREIGN KEY (`presp_id`) REFERENCES `pres_promos` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION;
/* On fait le transfert des données de la table actuelle vers la copy, ATTENTION: il faut le même nombre de colonnes */
INSERT INTO prestations_copy
SELECT * FROM prestations;
/* On modifie notre table copy de la façon que l'on souhaite */
ALTER TABLE `prestations_copy`
ADD COLUMN `seo_mot_clef` VARCHAR(50) NULL;
/* on supprime la table actuelle et renome la copy avec le bon nom de table */
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE prestations;
RENAME TABLE prestations_copy TO prestations;
SET FOREIGN_KEY_CHECKS=1;
누군가에게 도움이되기를 바랍니다.
문안 인사,
의지
SHOW CREATE TABLE tblname\G
,에 대한 요구 사항이 변경되는 열, 열의 데이터 유형과 열에 대한 새 이름을 보여줍니다.