Sunucu yeniden başlatıldıktan sonra Innodb veritabanında auto_increment kimliğinin sıfırlanmasını önle


11

Geçenlerde, sunucu yeniden başlatıldığında InnoDB'nin AUTO_INCREMENT değerini nasıl yeniden hesapladığı nedeniyle, kimlik listesinin üst ucundaki kayıtların kimliklerinin yeniden kullanılabileceğini okudum.

Normalde, bu bir sorun oluşturmaz, çünkü bir kullanıcı silindiğinde kimlikle ilişkili her şey diğer tablolardan da silinir.

Ancak kasıtlı olarak "İletiler = Kullanıcı # 123 =" olarak etiketlenmiş forum gönderimlerini yetim bırakıyorum, böylece geçmiş ileti dizileri korunuyor. Açıkça, bir kimlik tekrar kullanılırsa, bu bir sorun olacaktır.

Bu sorunu daha önce hiç yaşamadım, çünkü bir kimliğin bu şekilde tekrar kullanılmasını mümkün kılacak kadar yeni kullanıcı vardı. Ancak benim yeni proje kayıtları nadir ve etkin olmayan kullanıcı silme sıktır (özellikle "Açık Alfa" hesapları önizleme olarak yalnızca üç gün sürdüğü için) ve bu tür kimliklerin yeniden kullanımı üçte üç oldu.

Başka bir yerde AUTO_INCREMENT için doğru değeri kaydederek ve iç değerine güvenmek yerine kullanarak sorunu "düzeltti". InnoDB'nin gerçek son değeri hatırlamasının gerçek bir yolu var mı?


Okuduğunuz makaleniz var mı?
gbn



ALTER TABLE tablo_adı ENGINE = MyISAM Benim için çalışıyor. Masamız her zaman çok küçük tutulur, bu nedenle InnoDB'ye gerek yoktur.

1
@QuickFix Bunun neden işe yaradığına dair bazı ayrıntılar eklemelisiniz .
Max Vernon

Yanıtlar:


5

(asla silmeden sorunu önler)

"Posted by =User #123="Kullanıcıyı sildikten sonra bilgileri saklamak istediğiniz için id=123, kullanıcı verilerini depolamak için 2 tablo kullanmayı da düşünebilirsiniz. Biri Activekullanıcılar için ve biri için (etkin kullanıcılardan silinenler dahil). Ve bu kimlikleri asla AllUsertablodan silmeyin :

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

Bu elbette yeni kullanıcı ekleme işlemini zorlaştıracaktır. Herhangi bir yeni kullanıcı, her tabloda bir tane olmak üzere 2 kesici uç anlamına gelir. Ancak bir kullanıcıyı silmek ActiveUseryalnızca tablodan silinmek olacaktır . Tabloya atıfta bulunacak forum gönderileri hariç tüm FK'ler basamaklı olarak silinecektir Alluser(silme işleminin gerçekleşmeyeceği yerlerde).


4

Tüm sütunları auto_increment seçeneği ile kaydetmek için information_schema.tables kullanmak dışında bunu yapmanın doğal bir yolu yoktur.

Bu sütunları aşağıdaki gibi toplayabilirsiniz:

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 değerlerini sıfırlayacak bir komut dosyası oluşturun

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}

Daha sonra iki şeyden birini yapabilirsiniz:

SEÇENEK # 1: Başlangıçtan sonra komut dosyasını el ile çalıştırın

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

SEÇENEK 2: Bağlantılara izin vermeden önce mysqld'in komut dosyasını çalıştırmasını sağlayın

Bu seçeneği eklemeniz gerekir

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

Bu şekilde, mysql'i her yeniden başlattığınızda, bu komut dosyası başlangıçta yürütülür. Planlı bir mysql yeniden başlatmadan önce /var/lib/mysql/ResetAutoInc.sql dosyasını yeniden oluşturmayı hatırlamanız gerekir.



2

Sadece kullanıcıyı silmeyin. İlişkisel bütünlük daha önemlidir. Gizlilik nedeniyle veya başka herhangi bir nedenle yapmanız gerekiyorsa, kullanıcı adını 'silinmiş' olarak değiştirin ve diğer alanları temizleyin.


1

Bu eski bir sorudur ve hala konuyla ilgilidir.

1) Bu davranış, Mysql 8.0 ile giderilmektedir.

2) Bir çözüm, AUTO_INCREMENT'ı belirli bir değerin üzerinde tutmak için verilerinizde kukla bir satır kullanmaktır. Ne sakladığınıza bağlı olarak süper uygun değil, ancak bazı durumlarda basit bir çözümdür.


0

Bunun, bu yazıdaki talimatlara dayanarak kendi sistemimiz için ekstrapole edilmiş bir çözüme ihtiyacımız vardı. Bu, herkesin hedeflerine daha kolay bir şekilde ulaşmasına yardımcı olabilirse.

Sistemimiz, bağlantısı kesilmiş sistemlerde 2 yönlü senkronizasyon yaptığımız için silinen öğeleri saklamak için bir mezar taşı tablo deseni kullanır, bu nedenle mezar taşı tablolarını canlı tablolarıyla eşleştirmek ve mümkün olan en yüksek değeri elde etmek için bu kodu kullanırız :)

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 ;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.