서버 재시작 후 Innodb 데이터베이스에서 auto_increment ID 재설정 방지


11

최근에 서버를 다시 시작할 때 InnoDB가 AUTO_INCREMENT 값을 다시 계산하는 방식으로 인해 ID 목록의 최상위 레코드에 ID가 재사용 될 수 있음을 읽었습니다.

일반적으로 사용자가 삭제되면 ID와 관련된 모든 항목이 다른 테이블에서도 삭제되므로 문제가되지 않습니다.

하지만 포럼 게시글을 고아로 두어 "Posted by = User # 123 ="로 표시하여 지난 대화를 유지합니다. 분명히 ID를 재사용하면 문제가 될 것입니다.

ID를 재사용 할 가능성이 거의없는 새로운 사용자가 항상 있었기 때문에이 문제가 발생하지 않았습니다. 그러나 나의 새 프로젝트에서 가입은 드물고 비활성 사용자 삭제가 빈번하며 (특히 "Open Alpha"계정은 미리보기로 3 일 동안 만 지속되기 때문에) 이러한 ID 재사용은 현재 3 분 동안 3 번 발생했습니다.

AUTO_INCREMENT의 올바른 값을 다른 곳에 저장하고 내부 값에 의존하는 대신이를 사용하여 문제를 "수정"했습니다. InnoDB가 실제 마지막 값을 기억하도록하는 실제 방법이 있습니까?


읽은 기사가 있습니까?
gbn



ALTER TABLE table_name ENGINE = MyISAM 저에게 효과적입니다. 우리 테이블은 항상 매우 작게 유지되므로 InnoDB가 필요하지 않습니다.

1
@QuickFix 작동 하는지 에 대한 세부 사항을 추가해야 합니다.
Max Vernon

답변:


5

(삭제하지 않음으로써 문제 방지)

"Posted by =User #123="사용자를 삭제 한 후 정보 를 유지하려고하므로 id=123사용자 데이터를 저장하기 위해 2 개의 테이블을 사용할 수도 있습니다. 하나는 Active사용자를 위한 것이고 하나는 모두를위한 것입니다 (활성 사용자에서 삭제 된 것을 포함). 그리고 AllUser테이블 에서 해당 ID를 삭제하지 마십시오 .

CREATE TABLE AllUser
( user_id INT AUTO_INCREMENT
, ...
, PRIMARY KEY (user_id)
) ;

------
--- Forum posts FK should reference the `AllUser` table

CREATE TABLE ActiveUser
( user_id INT 
, ...
, PRIMARY KEY (user_id)
, FOREIGN KEY (user_id)
    REFERENCES AllUser (user_id)
) ;

------
--- All other FKs should reference the `ActiveUser` table

이것은 물론 새로운 사용자 삽입 작업을 복잡하게 만듭니다. 새로운 사용자는 각 테이블에 하나씩 2 개의 삽입물을 의미합니다. 사용자를 삭제하는 것은 ActiveUser테이블에서만 삭제하는 것입니다. Alluser테이블을 참조하는 포럼 게시물을 제외하고 계단식으로 모든 FK가 삭제됩니다 (삭제가 발생하지 않는 경우).


4

information_schema.tables를 사용하여 auto_increment 옵션으로 모든 열을 기록하는 것 외에는이 작업을 수행 할 수있는 자연스러운 방법이 없습니다.

다음과 같이 해당 열을 수집 할 수 있습니다.

CREATE TABLE mysql.my_autoinc ENGINE=MyISAM
SELECT table_schema,table_name,auto_increment
FROM information_schema.tables WHERE 1=2;
ALTER TABLE mysql.my_autoinc ADD PRIMARY KEY (table_schema,table_name);
INSERT INTO mysql.my_autoinc
SELECT table_schema,table_name,auto_increment
FROM information_schema.tables WHERE auto_increment IS NOT NULL;

auto_increment 값을 재설정 할 스크립트를 작성하십시오.

AUTOINC_SCRIPT=/var/lib/mysql/ResetAutoInc.sql
mysql -u... -p... -AN -e"SELECT CONCAT('ALTER TABLE ',table_schema,'.',table_name,' AUTO_INCREMENT=',auto_increment,';') FROM mysql.my_autoinc" > ${AUTOINC_SCRIPT}

그런 다음 두 가지 중 하나를 수행 할 수 있습니다.

옵션 # 1 : 시작 후 수동으로 스크립트 실행

mysql> source /var/lib/mysql/ResetAutoInc.sql

옵션 # 2 : 연결을 허용하기 전에 mysqld가 스크립트를 실행하도록하십시오

이 옵션을 추가해야합니다

[mysqld]
init-file=/var/lib/mysql/ResetAutoInc.sql

이렇게하면 mysql을 다시 시작할 때 마다이 스크립트가 처음에 실행됩니다. 계획된 mysql 재시작을 수행하기 전에 /var/lib/mysql/ResetAutoInc.sql을 재생성해야합니다.


3

5.5 문서는 당신이 이미 가지고있는 다른 곳에서 자동 증가 값을 저장하는 것이 좋습니다.

다른 해결책은 실제 테이블 자체에서 자동 증가를 사용하지 않도록 SEQUENCE를 에뮬레이트하는 것입니다. 이되었습니다 SO 이전에 논의 하고 다시 . MySQL의 성능 블로그 를 언급하고있다.

다른 RDBMS가 가지고 있지 않은 또 다른 MySQL 데이터 스크류


2

사용자를 삭제하지 마십시오. 관계 적 무결성이 더 중요합니다. 개인 정보 보호 사유 등으로 인해 필요한 경우 사용자 이름을 '삭제됨'으로 변경하고 다른 필드를 지우십시오.


1

이것은 오래된 질문이며 여전히 관련이 있습니다.

1)이 동작은 Mysql 8.0에서 수정되었습니다.

2) 한 가지 해결책은 데이터에 더미 행을 사용하여 AUTO_INCREMENT를 특정 값 이상으로 유지하는 것입니다. 저장 대상에 따라 매우 편리하지는 않지만 경우에 따라 간단한 솔루션입니다.


0

우리는이 게시물의 지침에 따라 자체 시스템에 대한 외삽 솔루션을 필요로했습니다. 이것이 더 쉬운 방법으로 목표를 달성하는 데 도움이 될 수 있다면.

우리 시스템은 연결이 끊긴 시스템에서 양방향 동기화를 수행하기 때문에 삭제 표시 항목을 저장하기 위해 삭제 표시 테이블 패턴을 사용합니다. 따라서이 코드를 사용하여 삭제 표시 테이블을 라이브 테이블과 일치시키고 가능한 가장 높은 값을 추출합니다.)

DROP PROCEDURE IF EXISTS `reset_auto_increments`;
DELIMITER $
CREATE PROCEDURE reset_auto_increments()
BEGIN

    DECLARE done INT DEFAULT 0;
    DECLARE schemaName VARCHAR(255) DEFAULT '';
    DECLARE liveTableName VARCHAR(255) DEFAULT '';
    DECLARE tombstoneTableName VARCHAR(255) DEFAULT '';
    DECLARE liveAutoIncrement INT DEFAULT 0;
    DECLARE tombstoneAutoIncrement INT DEFAULT 0;
    DECLARE newAutoIncrement INT DEFAULT 0;

    DECLARE autoIncrementPairs CURSOR FOR 
        SELECT
            liveTables.TABLE_SCHEMA AS schemaName,
            liveTables.TABLE_NAME AS liveTable, 
            tombstoneTables.TABLE_NAME AS tombstoneTable,
            liveTables.AUTO_INCREMENT AS live_auto_increment,
            tombstoneTables.AUTO_INCREMENT AS tombstone_auto_increment,
            GREATEST(liveTables.AUTO_INCREMENT, tombstoneTables.AUTO_INCREMENT) AS new_auto_increment
        FROM 
            information_schema.tables AS liveTables
            JOIN information_schema.tables AS tombstoneTables
                ON liveTables.TABLE_SCHEMA = tombstoneTables.TABLE_SCHEMA
                    AND CONCAT('deleted', UCASE(LEFT(liveTables.TABLE_NAME, 1)), SUBSTRING(liveTables.TABLE_NAME, 2))
                        = tombstoneTables.TABLE_NAME
        WHERE
            GREATEST(liveTables.AUTO_INCREMENT, tombstoneTables.AUTO_INCREMENT) IS NOT NULL;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    SET done = 0;

    SET schemaName = '';
    SET liveTableName = '';
    SET tombstoneTableName = '';
    SET liveAutoIncrement = 0;
    SET tombstoneAutoIncrement = 0;
    SET newAutoIncrement = 0;

    OPEN autoIncrementPairs;
    REPEAT

        FETCH autoIncrementPairs INTO 
            schemaName, 
            liveTableName, 
            tombstoneTableName, 
            liveAutoIncrement, 
            tombstoneAutoIncrement, 
            newAutoIncrement;

        SET @statement = CONCAT('ALTER TABLE ', schemaName, '.', liveTableName, ' AUTO_INCREMENT=', newAutoIncrement);
        PREPARE updateAutoIncrementStatement FROM @statement;
        EXECUTE updateAutoIncrementStatement;
        DEALLOCATE PREPARE updateAutoIncrementStatement;

    UNTIL done END REPEAT;

    CLOSE autoIncrementPairs;

END$

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