4

I am building a basic Rails app on Heroku (using postgresql and as db client PGAdmin)

I have a basic user table with name, email, password...

I have noticed that when I delete a user (for example user with id = 6) and then I add new users, the new user is not inserted on the id=6 (I'm talking of the first column on the left called on pgadmin "id PK Serial") so basically I have a lot of holes as during my training I often delete and add users.

So I end up having for the id column: id=1, id=5, id=9 id= 10...many holes.

Does it matter? Could it impact requests to the db I could need to do later on?

If I need to correct that and force the db to "fill" all the id slots, how should I do it?

user229044
  • 232,980
  • 40
  • 330
  • 338
Mathieu
  • 4,587
  • 11
  • 57
  • 112

2 Answers2

4

It is absolutely normal to have "holes" in table identity sequences - even if you have never deleted a row. I wrote more about this in this earlier answer.

PostgreSQL sequences are, by design, exempt from normal transactional rules. If they were not then only one transaction at a time could acquire an ID, so you'd never be able to have more than one session inserting into a table at a time. This would lead to miserable performance.

This is explained in the PostgreSQL manual on the nextval call - the call that get values from sequences:

Important: To avoid blocking concurrent transactions that obtain numbers from the same sequence, a nextval operation is never rolled back; that is, once a value has been fetched it is considered used, even if the transaction that did the nextval later aborts. This means that aborted transactions might leave unused "holes" in the sequence of assigned values.

In theory PostgreSQL could maintain a list of deleted, abandoned and unused IDs, but in practice this is prohibitively expensive in performance terms - and extremely hard to implement. Once an application gets an id with nextval it's free to use it at any time in the future and some applications use exactly that approach, caching blocks of IDs for better internal concurrency.

Consider generated IDs to be a unique row number - and that's all. It doesn't tell you how many rows there are. It doesn't tell you if one row was inserted after another row (you can use a created_time timestamp, possibly maintained by a trigger, for that). It doesn't tell you if one row was committed after another row (the system xmin columm tells you that, with certain limitations). All it tells you is how to find the row.

See:

Community
  • 1
  • 1
Craig Ringer
  • 307,061
  • 76
  • 688
  • 778
1

It's normal Rails behavior to have these gaps between IDs after doing deletes.

It's advisable to not change that, because you might want to later track user actions and want to either just go through the logs and find relevant log entries or you might want to add tables which store the history of what a user did to change a model (e.g. when it was deleted / changed).

In both cases you don't want to end up with the confusion caused by two different instances using the same ID -- hence: do not re-use IDs.

Tilo
  • 33,354
  • 5
  • 79
  • 106
  • It's not just deletes; if you're using `SEQUENCE`s then even an insert-only table can have gaps. See http://www.postgresql.org/docs/current/static/functions-sequence.html – Craig Ringer Jun 01 '13 at 03:35