SQLite
 sql >> Datenbank >  >> RDS >> SQLite

Funktionsweise von AUTOINCREMENT in SQLite

In SQLite ein AUTOINCREMENT Spalte verwendet einen automatisch inkrementierten Wert für jede Zeile, die in die Tabelle eingefügt wird.

Es gibt mehrere Möglichkeiten, ein AUTOINCREMENT zu erstellen Spalte:

  • Sie können es implizit erstellen, wenn Sie die Spalte als INTEGER PRIMARY KEY definieren .
  • Sie können es explizit mit dem AUTOINCREMENT erstellen Stichwort. Ein Nachteil dieser Methode ist, dass sie zusätzlichen CPU-, Arbeitsspeicher-, Festplattenspeicher- und Festplatten-E/A-Overhead verbraucht.

Beide Methoden bewirken, dass die Spalte jedes Mal einen inkrementierenden Wert verwendet, wenn eine neue Zeile mit NULL eingefügt wird in dieser Spalte.

Es gibt jedoch einige subtile Unterschiede zwischen der Funktionsweise der einzelnen Methoden.

Ohne das Schlüsselwort AUTOINCREMENT

Wenn Sie eine Spalte als INTEGER PRIMARY KEY deklarieren , wird es automatisch erhöht. Daher müssen Sie das AUTOINCREMENT eigentlich nicht verwenden Schlüsselwort, um eine Spalte zu haben, die einen automatisch inkrementierenden Wert für jede Zeile verwendet.

Wenn Sie dies tun, wird jeder NULL Werte werden in die aktuelle ROWID konvertiert . Mit anderen Worten, wenn Sie NULL einfügen in diese Spalte, wird sie in die aktuelle ROWID konvertiert .

Tatsächlich funktioniert es so, dass die Spalte ein Alias ​​für die ROWID wird . Sie können auf die ROWID zugreifen Wert, indem Sie einen von vier Namen verwenden; der Spaltenname, ROWID , _ROWID_ , oder OID .

Ein Vorteil des Weglassens des AUTOINCREMENT Das Schlüsselwort ist, dass es CPU-, Arbeitsspeicher-, Festplattenspeicher- und Festplatten-E/A-Overhead reduziert.

Ein wichtiger Nachteil ist jedoch, dass Sie nicht garantieren können, dass alle Zeilen in aufsteigender Reihenfolge inkrementiert werden. Dies liegt an der Art und Weise, wie die automatische Inkrementierung funktioniert, wenn das AUTOINCREMENT weggelassen wird Schlüsselwort im Vergleich zur Verwendung dieses Schlüsselworts.

Wenn Sie AUTOINCREMENT weglassen Stichwort, einmal ROWID gleich der größtmöglichen ganzen Zahl (9223372036854775807) ist, versucht SQLite, eine unbenutzte positive ROWID zu finden zufällig.

Allerdings, solange Sie niemals die maximale ROWID verwenden Wert und Sie löschen nie den Eintrag in der Tabelle mit der größten ROWID , generiert diese Methode eine monoton ansteigende eindeutige ROWID s.

Mit dem Schlüsselwort AUTOINCREMENT

Sie können auch explizit automatisch inkrementierende Spalten erstellen. Verwenden Sie dazu das AUTOINCREMENT Stichwort.

Wenn Sie diese Methode verwenden, wird ein etwas anderer Algorithmus verwendet, um den automatisch inkrementierten Wert zu bestimmen.

Wenn Sie das AUTOINCREMENT verwenden Schlüsselwort, die ROWID Die für die neue Zeile gewählte Zahl ist mindestens um eins größer als die größte ROWID das hat immer zuvor in derselben Tabelle existierte.

Mit anderen Worten, es wird nicht zurückgehen und zuvor gelöschte ROWID wiederverwenden Werte. Einmal die größtmögliche ROWID eingefügt wurde, sind keine neuen Einfügungen zulässig. Jeder Versuch, eine neue Zeile einzufügen, schlägt mit einem SQLITE_FULL fehl Fehler.

Daher garantiert die Verwendung dieser Methode, dass die ROWID s sind monoton steigend. Mit anderen Worten, Sie können sich auf diese Methode verlassen, um ROWID zu haben s in aufsteigender Reihenfolge.

Dies bedeutet jedoch nicht, dass die Werte immer um 1 erhöht werden. Es bedeutet nur, dass sie niemals abnehmen werden.

Beispiel

Hier ist ein Beispiel, um den Unterschied zwischen der impliziten und der expliziten Definition einer Auto-Increment-Spalte zu demonstrieren.

CREATE TABLE Cats( 
    CatId INTEGER PRIMARY KEY, 
    CatName
);

CREATE TABLE Dogs( 
    DogId INTEGER PRIMARY KEY AUTOINCREMENT, 
    DogName
);

INSERT INTO Cats VALUES 
    ( NULL, 'Brush' ),
    ( NULL, 'Scarcat' ),
    ( NULL, 'Flutter' );

INSERT INTO Dogs VALUES 
    ( NULL, 'Yelp' ),
    ( NULL, 'Woofer' ),
    ( NULL, 'Fluff' );

SELECT * FROM Cats;
SELECT * FROM Dogs;

Erstes Ergebnis:

CatId       CatName   
----------  ----------
1           Brush     
2           Scarcat   
3           Flutter  

DogId       DogName   
----------  ----------
1           Yelp      
2           Woofer    
3           Fluff      

Lassen Sie uns nun die letzte Zeile in jeder Tabelle löschen, die Zeilen erneut einfügen und dann das Ergebnis auswählen:

DELETE FROM Cats WHERE CatId = 3;
DELETE FROM Dogs WHERE DogId = 3;

INSERT INTO Cats VALUES ( NULL, 'New Flutter' );
INSERT INTO Dogs VALUES ( NULL, 'New Fluff' );

SELECT * FROM Cats;
SELECT * FROM Dogs;

Ergebnis:

CatId       CatName   
----------  ----------
1           Brush     
2           Scarcat   
3           New Flutter

DogId       DogName   
----------  ----------
1           Yelp      
2           Woofer    
4           New Fluff 

Um es noch einmal zusammenzufassen:die Katzen Tabelle wurde ohne erstellt das AUTOINCREMENT Schlüsselwort und die Hunde Tabelle wurde mit erstellt das AUTOINCREMENT Schlüsselwort.

Nach dem Löschen der letzten Zeile aus den Cats Tabelle, das nächste INSERT Der Vorgang führte zu derselben ROWID für diese Zeile wiederverwendet wird.

Aber die Hunde Tisch war anders. Es wurde mit dem AUTOINCREMENT erstellt Schlüsselwort und kann daher den vorherigen Wert nicht wiederverwenden. Es wird einfach zum nächsten Wert hochgezählt, wobei eine Lücke in der Nummerierung bleibt.

Maximale ROWID

Wir können das vorherige Beispiel noch einen Schritt weiterführen und eine neue Zeile einfügen, indem wir explizit die maximale ROWID verwenden möglich.

INSERT INTO Cats VALUES ( 9223372036854775807, 'Magnus' );
INSERT INTO Dogs VALUES ( 9223372036854775807, 'Maximus' );

SELECT * FROM Cats;
SELECT * FROM Dogs;

Ergebnis:

CatId                 CatName             
--------------------  --------------------
1                     Brush               
2                     Scarcat             
3                     New Flutter         
9223372036854775807   Magnus              

DogId                 DogName             
--------------------  --------------------
1                     Yelp                
2                     Woofer              
4                     New Fluff           
9223372036854775807   Maximus             

OK, also verwenden beide Tabellen die größtmögliche Ganzzahl als ihre größte ROWID Werte.

Mal sehen, was passiert, wenn ich versuche, eine neue Zeile in jede Tabelle einzufügen (ohne explizit einen Wert für die automatisch inkrementierenden Spalten anzugeben).

In die Katzen einfügen Tabelle:

INSERT INTO Cats VALUES ( NULL, 'Scratchy' );
SELECT * FROM Cats;

Ergebnis:

CatId                 CatName             
--------------------  --------------------
1                     Brush               
2                     Scarcat             
3                     New Flutter         
267244677462397326    Scratchy            
9223372036854775807   Magnus              

Also die Katzen Tabelle war erfolgreich. Beachten Sie jedoch, dass der neue automatisch inkrementierende Wert niedriger ist als der vorherige Wert (es gibt keine andere Option).

Ohne eine andere Spalte zum Aufzeichnen des Datums/der Uhrzeit, zu der die Zeile eingefügt/aktualisiert wurde, könnte man fälschlicherweise annehmen, dass Magnus wurde nach Scratchy eingefügt .

Versuchen wir nun, eine neue Zeile zu den Dogs einzufügen Tabelle:

INSERT INTO Dogs VALUES ( NULL, 'Lickable' );

Ergebnis:

Error: database or disk is full

Wir erhalten also ein anderes Ergebnis als bei den Cats Tabelle.

Ich habe diesen Fehler bekommen, weil die größtmögliche ROWID bereits in der Tabelle verwendet wird, und weil diese Tabelle mit dem AUTOINCREMENT erstellt wurde Schlüsselwort, es wird nicht zurückgehen und nach einer unbenutzten ROWID suchen Wert.

SELECT * FROM Dogs;

Ergebnis:

DogId                 DogName             
--------------------  --------------------
1                     Yelp                
2                     Woofer              
4                     New Fluff           
9223372036854775807   Maximus             

Außerdem bekomme ich diesen Fehler weiterhin, auch wenn ich Maximus lösche aus der Tabelle (also der Hund mit der höchsten ROWID). Wert).

Versuchen wir es:

DELETE FROM Dogs WHERE DogId = 9223372036854775807;
INSERT INTO Dogs VALUES ( NULL, 'Lickable' );

Ergebnis:

Error: database or disk is full

Wir bekommen also nicht nur einen Fehler, sondern ich habe auch Maximus gelöscht :

SELECT * FROM Dogs;

Ergebnis:

DogId                 DogName             
--------------------  --------------------
1                     Yelp                
2                     Woofer              
4                     New Fluff           

Es ist wichtig zu beachten, dass dies auch dann geschieht, wenn ich die ROWID ändere Wert auf einen niedrigeren Wert. Die Tatsache, dass ich bereits eine ROWID von 9223372036854775807 verwendet habe, bedeutet, dass AUTOINCREMENT wird nicht mehr automatisch hochgezählt.

Das liegt daran, dass AUTOINCREMENT verwendet nur Werte, die mindestens um eins höher sind als alle Werte, die jemals zuvor in derselben Tabelle existierten .

Wenn ich von nun an weiterhin Werte in diese Spalte einfügen wollte, müsste ich den Wert explizit einfügen. Dies setzt voraus, dass ich nicht bereits 9223372036854775807 Zeilen in der Tabelle habe.

Lassen Sie uns Maximus wieder einfügen mit einer niedrigeren ROWID und versuchen Sie es erneut:

INSERT INTO Dogs VALUES ( 5, 'Maximus' );
SELECT * FROM Dogs;

Ergebnis:

DogId                 DogName             
--------------------  --------------------
1                     Yelp                
2                     Woofer              
4                     New Fluff           
5                     Maximus            

Versuchen wir nun, Lickable einzufügen erneut mit AUTOINCREMENT :

INSERT INTO Dogs VALUES ( NULL, 'Lickable' );

Ergebnis:

Error: database or disk is full

Also, obwohl ich die Zeile gelöscht habe, die die maximale ROWID enthält Wert von 9223372036854775807, immer noch hindert mich daran, die Spalte automatisch zu inkrementieren.

Genau so wurde es konzipiert. Die maximale ROWID zuvor in dieser Tabelle gewesen ist und daher AUTOINCREMENT wird in dieser Tabelle nicht automatisch wieder hochgezählt.

Die einzige Möglichkeit, dieser Tabelle eine neue Zeile hinzuzufügen, besteht darin, die ROWID manuell einzufügen Wert.

INSERT INTO Dogs VALUES (6, 'Lickable');
SELECT * FROM Dogs;

Ergebnis:

DogId                 DogName             
--------------------  --------------------
1                     Yelp                
2                     Woofer              
4                     New Fluff           
5                     Maximus             
6                     Lickable