Soft delete
Nikolay: Hello, this is PostgresFM.
I don't remember the number of episodes.
This is Nikolay Samokhvalov from Postgres.AI and my co-host as
usual, Michael Christofides from pgMustard.
Hi, Michael.
Michael: Hello, Nikolay.
I think this is 103.
Nikolay: Okay, not bad.
So we discussed what?
Michael: Yeah, so it's one of those things that's come up in discussion
a few times.
And we said we should do an episode on that one day.
And so we finally got to it and it's soft deletes, which is a
pattern that a lot of us have come across whilst working with
databases more generally.
It's not specific to Postgres, but it's the idea of instead of
deleting data, not deleting it, but hiding it from the application
in some way.
Nikolay: Let me explain it for regular, like how it feels since
I've built three social networks in the past.
I used soft deletes a lot, of course.
And then like Postgres is not good with deletes due to how MVCC
is organized, vacuum and so on.
Deletes are not good, right?
It's like an old idea.
Although each update consists of delete and insert at a physical
level, right?
Unless it's a hot update.
So how it feels in the eyes of millions of users I know, and
it's not only about the projects I've built, like almost any
social media uses it.
You go and try to unregister your account, you press all the
buttons say delete me or something like everything or just I
don't know sometimes you need to write to support or something
but usually it's good services have this button ready for you
right So I want to delete my account fully.
And then you find out that, for example, depending on implementation,
then you find out that your page is, I don't know, some small
artifacts you can see and feel that your page was not fully deleted
or your account was not fully deleted.
One of these artifacts, not artifacts, signs that SoftDelete is
used is You can actually restore it, right?
Easy, right?
You can, for example, Facebook.
Try to delete yourself on Facebook.
It will give you many chances to restore, and even after you
delete it, you still can restore it.
So you can, like, one month later, you can just press a button
and restore.
If you, like, what users want when they are angry about some
service?
They don't want to deal with it
completely, like, something can
happen in their lives, right?
They can see having an account
as a problem, for example.
They think it's a mistake to post
such pictures or to do some
conversations.
It doesn't matter.
I want to delete it.
I'm a new person right now.
It's there, right?
So, delete.
But then the server says, you can
restore.
Did you delete my data or no?
And then compliance, we have also
interesting points.
In some cases, we have mandatory,
like demand to store data sometimes.
Right?
Michael: We have both sides, right?
Yeah, we have laws that demand
we have to store data for a certain
amount of time in some environment.
Nikolay: And vice versa.
Sometimes if user decides the service
must delete data.
So delete, the word delete has
many meanings, right?
It's not SQL statement delete.
When you delete your account, it
doesn't mean the service executed
actually delete.
Most likely they just executed
updates or delete with triggers
and so on.
We will discuss, dive into details.
But for users, it's really annoying
to feel lack of ability to
truly delete.
I must say, like I saw it and I
was on the other side of, I was
on both sides many times actually.
And I know how it feels when you
want to delete for sure, like
100% I won't delete my data, it's
my data deleted.
No, you can restore it means it
was not actually deleted.
Michael: Yeah, for sure.
Well, I think we can come back
to like,
Nikolay: technical
Michael: the user side.
Well, I think there's I think there's
so many parts of this that
are interesting.
1 is kind of, If you do decide
you want this as a provider, implementation
details are quite interesting and
there are different and Postgres
specific details are quite interesting
as well.
But from the usability side of
it, there are different implementations.
I think various companies and organizations
are implementing
features around deletion, around
kind of making sure people know
exactly what they're doing before
hitting delete, you know, write
the words of your account name
in here.
Everyone's come across these kind
of make sure you type out,
yes, I'm sure I really want to
delete my account and I will not
beg support to undelete it later.
Nikolay: We give you 1 month to
make, to reconsider it or something.
Michael: Exactly, Or we can recover
it, but only in the next
30 days.
Type them.
Yeah, exactly.
Nikolay: I remember another way,
another sign that you can see
that soft delete was applied is
instead of having 404 error,
404 error, you go to your X page,
like you deleted it, but you
see something like account deleted.
It means that records still exist
in database, right?
Just changed its status.
So status like active, deleted,
right?
Pending, like pending, pending,
it means you need to activate
it, like email activation or something,
phone activation.
Then it's active and then it's
deleted, lifecycle, right?
Michael: In my mind, that's kind
of like a bug though, right?
Like that's just a poorly implemented
soft deletion.
Nikolay: Yeah, but it's so common.
And I actually implemented, I implemented
soft deletes in many
various ways.
But honestly, this morning, thinking
like walking my dog, By
the way, hello to everyone who
is running, walking dog, like,
I don't know, like riding bicycle.
Yeah.
I know we promised to keep 30 minutes,
but it's good for you
to run longer and ride bicycle
longer and for your dog as well.
So walking my dogs I was thinking,
soft delete, soft delete.
I also chatted with our bot to
like to brainstorm what to discuss
and I realized that if I needed
to implement it right now, looking
like back to my 20 years of experience,
3 social networks and
many other systems and our customers,
all those ways to implement
soft delete, what would I choose
now?
I don't know.
Maybe by the end of this discussion,
I will have some clarity.
But it's so difficult.
It's not an easy topic, actually.
I expected a simple topic today.
Michael: I think it's simple if
you only consider a single case
at a time.
If you want to give generic advice,
I think it becomes more complicated.
And we also dove into the most
complicated version, which is
deleting a whole account which
has multiple things.
Nikolay: Yeah, let's talk about
only 1 table.
Yeah, propagation is a different
topic.
Consider only 1 table.
We have many choices.
For example, 1 I already discussed,
like status.
You have pending, active, deleted,
something, archived.
Or it can be a different column
is deleted by default.
It's false, you can set it to true.
Both are very similar approaches.
Both I don't like at all.
Michael: I quite like deleted at,
which is with it being null
by default, and then a timestamp
as to when it was deleted.
Right.
Nikolay: I would not choose these
approaches.
Neither of them.
Today.
I chose them in the past.
Yeah.
Today, no, thank you.
Why?
Because then you need to deal with,
like, optimizing your queries,
thinking about indexes.
Most of the time, queries work
with active data.
So you need to keep all your indexes
probably partial with the
WHERE clause having this filter
to deal only with active records.
And you accumulate like non-active
data set in the same table,
which is not useful at all, right?
So and also foreign keys.
Michael: Yeah, unique constraints.
There's so many downsides.
Nikolay: That's complexity.
Michael: Well, and you need to,
you need to adapt your, your
application to always view things
where deleted at is not.
Because otherwise people will see
deleted data.
So there is definitely complexity
to that, but implementation-wise,
I think it's on the simpler side.
I think there are some advantages.
Nikolay: I maybe would choose it
only if I know that deletes
will be much less than 1% of all
data.
But who knows in advance, right?
Maybe we will need to delete a
lot.
Sometimes, from social media experience,
spammers, in ways they
come, They can register a million
accounts and you need to delete
them.
At the same time, to follow your
procedures you developed, if
you developed a soft deletes approach,
you're deleting fake accounts
is also deletes, right?
So you need to still keep them
in the same table and it's like
a lot of records which will sit
on the disk and most importantly
in memory, in caches.
Michael: Let's talk about the use
cases for it because I think
they're different enough that I
think it will then become clearer
when we would use different ones.
Like, for example, I think the
primary use case, the only use
case I've ever used Soft Deletes
for in the past, I've always
been at companies and working on
products where we haven't done
soft deletes by default.
I've only ever had it implemented
it once for an application
because several times a year, we
were restoring data that had
been deleted accidentally or prematurely.
So it was a,
Nikolay: and you didn't have that
by slab to, to, to go back
in time.
Easily.
Michael: We could risk the solution.
We, we, this is actually on the
Microsoft SQL Server database
at the time.
And we would actually restore from
a backup.
That's what we'd end up doing.
Nikolay: It takes many hours.
Michael: The larger the database,
the longer it takes.
And it's painful and manual.
And we were doing this often enough
that we decided to implement
soft deletes.
But with a slight difference.
I think sometimes people describe
soft deletes as if it's like
permanently gonna be in that soft
deletion state we would do
it and then have a like a Cron
job that anything older than so
people would delete something by
mistake and very quickly email
support and say, I deleted the
wrong project in this case.
Nikolay: We need to restore.
Yeah.
And restore procedures is complex.
Michael: Yeah, but it was always
quickly.
It was always within a day
Nikolay: or 2.
It's quicker.
Michael: No, sorry.
So in this case, with this application,
people that delete things
accidentally, they knew pretty,
like almost straight away that
they had done it and that they'd
regretted doing it.
So we knew we could, for example,
have this data in in a soft
deleted fashion with deleted app
with a timestamp.
And then we could have a cron job,
hard delete, or actually delete
data that was more than like, that
was deleted app more than
30 days ago.
So in that case, it meant we could
keep the structure simple,
only add 1 column, update the application
only in a few places
to view the data that wasn't deleted
yet.
You know, so it was a relatively
simple case where we were having
to restore data from time to time.
Nikolay: It's a good point.
So I took extreme case when we
discuss accounts and it's like
sensitive to like personal feelings
are affected.
But you're describing basically
the same thing as emails in Gmail
and Recycle Bin or like how it's
called trash folder.
Michael: Yeah, like on a desktop.
Yeah.
Nikolay: Right.
So you put it there basically when
you do deletes and it sits
there for 30 days, right?
And then automatically hard deleted.
Michael: Exactly.
Nikolay: And you can restore it
anytime and users usually appreciate
this feature and consider it as
good if you can undo your action.
I agree.
Like when we talk about some objects
inside the account, right?
So some data.
Michael: The only difference is
in this case is we didn't implement
the ability to view what's in the...
Like in those 2 cases, what we
could have done.
And that's actually, potentially
would have been nice for users.
Nikolay: Yeah, actually in this
case, this approach, now I'm
thinking, yeah, in this case, I
would probably choose some status
approach because it's actually
the same data, we just don't show
it in 1 place, but we show it in
another place.
So it's just some category, that's
it.
Right?
You're right.
So in this case, I would prefer
actually status, maybe timestamp
of changes, but maybe I would put
timestamps to special different
like audit, like log style append
only table to track actions
when some action was done.
Yeah, but you're right, actually.
Maybe this case, let's call it
in-place soft-delete when we keep
data in the same table and so on.
Michael: I was thinking use-case-wise,
that's if you're implementing
it to avoid or to make restoration
easier or undelete easier.
Nikolay: And viewing deleted data,
if some in some cases like
trash, trash data, if you want
to allow users to review it, Why
not?
Michael: Yeah, well, that's the
other like, there's another use
case for soft deletes I've heard
and seen people write about
which is to give you the ability
to examine it or to audit it
or to look through why it was done
or who did what.
So I think there are some...
Exactly.
And I know we've had a whole episode
on audit, but it could be
not necessarily for regulatory
purposes, but it could be for
debugging purposes.
Nikolay: And there we can have
a hard delete button for users
as well.
If like only there, not in main
place, but for like if object
already soft deleted, we could
allow users to actually delete.
But let's talk about Postgres spec.
This is UX discussion.
What else?
Compliance.
Sometimes you do need to delete
data for sure, like keeping it
only in some backups and also have
some policy to delete there
as well.
I mean, backups should be deleted
as well at some point.
Sometimes you do need to keep information
and soft deletes help
to comply some policies and regulations.
Depending on law you need to follow,
like it's hard.
But honestly, I prefer, speaking
of law, I prefer when I need
to delete everything.
But for convenience and as a business
owner, it's actually much
more convenient if you still have
data all the time and you can
review what happened and restore
it?
Well, sometimes, depending on the
nature of your business.
I see more and more guys follow,
like, it's like some compliance
rules, but I see more and more
companies implement the rule that
Slack deletes messages after some
time and everything is deleted.
I don't know.
Maybe it's because of costs.
Maybe it's some compliance, actually.
I don't know.
Michael: Well, I think there was
an age where this going back
to kind of philosophical side of
things, but I think there was
a time where people, I remember
reading headlines like data is
the new oil and things like that
and people thought hoarding
as much data or gathering as much
data as they could would be
valuable in the future for analysis
reasons or for mining, that
kind of thing.
And I feel like with a lot of data
breaches, especially, sorry,
I think I've got a siren in my
background, with data breaches,
I still feel like things flipped
and people started to think
of having data as a liability.
And the more data they held, or
the more personal it was, the
more at risk they are of, or the
bigger target they become for
attacks.
I feel like that's changed even
within the last, well, even within
my career of how people view holding
data if you don't really
need it.
Nikolay: Yeah.
Also performance reasons.
If you keep everything, it's hard.
I see many successful e-commerce
companies, they do need to actually
delete data, and having soft deletes,
they at some point decide
to clean up and actually delete
data.
So in place of soft delete, you
just have a column or a couple
of columns, and then you have a
lot of partial indexes, obviously,
maybe.
Right?
Maybe.
Maybe not.
It depends on the distribution
and selectivity you have.
And how could we improve this?
What about having a special partition
or a set of partitions
and include this column to partition
key.
It would be transparent for application
if we update status setting
from active to deleted.
In this case, the row will be deleted
in the main partition,
like actual working partition and
it will go to this kind of
archive partition, right?
Michael: Yeah, it would be like
moved.
So I guess it's similar in terms
of like write-ahead log impact
and but actually could it be higher?
I guess you're forcing no hot updates
but I'm guessing you're
not going to get hot updates anyway
because it's the delete that.
Nikolay: Yeah.
You cannot have hot update here.
So 0 chances because it's actually
deleted, actually inserted.
I guess hat updates is a good thing
to have, but in this case
you should avoid partial...
Back to a single table and just
a column.
If you want hot updates to be used
when you update this column,
you cannot use this column in partial
indexes in the where clause
of those indexes.
You must avoid it.
It works well only if you have,
as I said, only low part of your
table of deletes.
Like deletes are rare.
Michael: Yeah.
So another, like another solution
I see mentioned that I've not
used is using a view.
So defining a view where deleted
at is, has no value for example.
Nikolay: Yeah, I don't know.
You know like when you're in love
with something many years and
then this love is converted to
hate.
This is my relationship with views
because my, yeah, my thesis,
martial arts master, I don't remember,
was about updatable views
and then updatable XML views and
like, oh, I spent so much time
and I worked with them so much
time.
Now the only views I can deal with
now these days myself in my
projects where I have full control.
Only Postgres views.
Michael: That's it.
Nikolay: Everywhere else I avoid
them because I don't want to
deal with dependency hell later.
Because it's just a lot of overhead.
You just change something or add
column or drop column.
You need to recreate your views
and logs and logs when you issue
DDL, like, I don't want this.
But Yes, views can be used in many
cases, but you cannot create
an index on a regular view.
Again, I'm speaking of performance.
Just views will hide it, right?
And that's it.
I mean, hide some rows.
Michael: Exactly.
But it also makes the implementation
a little bit easier because
you don't have to update.
You don't have to make the application
aware of your soft delete
implementation.
Nikolay: Well, yeah.
Michael: You could just point the
application at the view now.
The Application doesn't
Nikolay: see those rows at all,
right?
Michael: Should we move on to some
other, like...
Nikolay: Approach.
Separate table approach.
Michael: Yes.
Nikolay: So straightforward approach.
Let's just have the table with
same structure, right?
Maybe not the same set of indexes
because we don't need all of
them, maybe, right?
And just insert to that table,
maybe using some trigger when
delete happens.
Michael: Yeah, so the 2 approaches
I've had are a shadow table
for each table that you want to,
yeah.
I don't know if that's the correct
term.
Nikolay: And I also hated this.
Because DDL, maintaining schema.
Michael: But I did see a neat alternative
to this in a blog post
by Brander, who's got a couple
of blog posts about DDL.
Nikolay: So let's discuss why it's
bad, like in detail, just
to clarify.
Good idea.
First of all, you need to create,
if you have many tables where
you want soft delete to be implemented,
you always need additional
table.
It's just overhead.
And also you need, every time you
create a column, for example,
or a name column or something,
you also need not to forget to
do it in the shadow table.
And living with such schema many
years in 1 project, I must admit,
it's a huge headache.
People always forget it.
You can try to invent some procedures
and automation not to forget
it, but still, deployments to production
when shadow table DDL
was forgotten, quite significant
risk.
So It's a lot of objects to deal
with.
Of course, you can put it to some,
say, schema named shadow,
for example, and keep the table
names exactly the same as in
the original schema, public or
something new, if it's a new project.
So public schema is not popular
anymore, right?
So, and it's good because it means
convenience because exactly
the same table names, but it introduces
a lot of overhead, it
requires good culture of automation,
like tooling, not to be,
to be always in a consistent state.
Michael: Yeah, I think there was
a lot, there are a lot of difficulties
as part of this.
Obviously, it does come with some
benefits, like easier to restore
than the next, the alternative
way of doing this.
Nikolay: Let me guess about alternative
way.
I also implemented it.
I didn't read this post by Brandur,
but I can guess because I
also implement I think we walked
on the same paths, right?
So you create a single table with
probably like some ID maybe
some surrogate ID then table name
who deleted timestamp and then
just JSON or JSONB column where
you just put all the data from
any table.
Right.
And you can...
Exactly.
Okay.
Why not?
Preserving column names maybe even.
Right.
So you...
Michael: Yes.
I think they used like a to JSONB
function.
Nikolay: Right.
And you do everything in triggers,
so everything again is transparent.
When a delete statement happens,
your row from any table which
has this trigger is packed and
sent to this table.
Very convenient.
I like this schema.
Michael: It's super.
So again, this is optimized for
like, this is harder to restore
from, right, because it's now in
a difficult format.
And especially if like the schema
has changed in between.
Nikolay: Well, this is a price.
You have trade-off.
Either you survive any schema changes
easily, or you need to
deal with some mutations during
restore.
You need to understand, okay, this
delete happened A year ago,
we had a different schema.
What to do?
You do need to do this.
Or you deal with schema...
You need to maintain mirror schema
changes all the time.
I would prefer actually deal with...
Since restore...
Depending on the project, of course.
If restore is not super common,
I would prefer this schema.
Super convenient, super universal.
Michael: Yeah, me too.
I think there's a lot of benefits
here.
Not for the 1 case I did implement
soft deletes in the past,
where the whole point was to make
restoration easier in a very
small number of cases.
This case is very different to
that.
But yeah, I do think there are
some tricky parts of this, though,
I think, for example, the compliance
thing is tricky here.
Like, it's another place that you
need to remember to delete
data from in the future.
If you get a GDPR request, you
can't just search on normal tables
for that data.
You also have to search this delete
log.
And it might be tricky to search
because it's JSON B data with
like unstructured.
So there's a there I think there
are downsides.
Nikolay: Right.
Is it fair to call this soft delete?
Maybe it should be called just
archiving?
Michael: Good point.
There's no definition of soft delete
that I know of.
It's not part of the SQL standard.
So I think it's more around like
what are the, what's it for?
And maybe we've lost sight of like
why are we implementing this
feature?
If it's for easy undeletes, maybe
this isn't the right solution.
But if it's for debugging or if
it's for different purposes,
then yeah, archiving makes some
sense.
But I guess it is, it's deleting
it in a way that it's not deleted.
That is the, you know, you mentioned
the, as a user seeing some
signs that it wasn't deleted, this
avoids a lot of those, right?
Like it's not in the same table
anymore.
Nikolay: Yeah.
Application can, If we define the
trigger function with security
definer, we can revoke or just
do not grant any permissions to
application user to deal with schema
or this table.
And that's it.
So application won't be able to
reach the data at all.
At very low, like, I mean, at database
level, database guarantees,
it's not possible.
But at the same time, Trigger can
still insert it because it
has...
Trigger function has security definer,
meaning that it has permissions
to run queries which are inside
the function using the level
of access of the user who defined
this function.
Michael: Cool.
I didn't know you could do that.
That's very cool.
Nikolay: It's called security definer.
When you create a function, trigger
function, for trigger you
need to create a function, you
just say Security Definer.
And I like it because you can encapsulate
some actions which
normal user, application user,
When I say application user, I
mean database user which is used
by your application.
Usually there are some tables that
this user cannot access.
For example, this shadow table
or shadow schema with multiple
tables.
But I still prefer single table.
But you can still allow, for example,
specific insert encapsulated
in this function and just grant
permissions for specific action
indirectly via the security definer.
Michael: Nice.
I like it.
Nikolay: Yeah.
I use it all the time for many
cases.
So yeah, better control what can
be done, what cannot be done.
So you basically it's good for
security reasons.
It's good to forbid everything
first as first thing, and then
just allow some specific action
in very controlled manner.
Intrigue.
Michael: I feel like there's a
phrase for this, isn't it?
Like security by minimum permission
or something.
I can't remember what the phrase
is.
It's like a security principle
of least permission, give things
the least permission they need.
Right, right,
Nikolay: right.
Well, in former life, we called
it a blacklisting, white listing.
I don't know why now it's not possible
to tell this, right?
But it means that you will just
say nothing is possible except
this, right?
And yeah, it's good.
So yeah, it's a good approach,
but you are right, Restoration
will be tricky.
You need to develop specific procedures,
deal somehow with schema
evolution.
And in this case, I would say if
we talk about some account deletion,
I would do this.
If we talk about something like
we have some objects user can
create, modify, or delete, and
we want support undo for deletion,
Like in Gmail with emails, when
you just delete email, it goes
to trash, and then you can undo
or delete forever, right?
There's a button, delete forever.
This is hard to delete.
In this case, I would prefer maybe
still in place, like in the
same, like just a column in the
same table status or something.
Michael: Nice.
Nikolay: Right, right.
Both are, we can say, both are
soft deletes with their own pros
and cons.
Michael: Yeah, seems very reasonable.
Nikolay: Do you think they can
coexist in the same project?
Not because they are, like decisions
were made by different persons,
different
Michael: developers.
I think I genuinely think that
the end of Brando's blog post,
he mentioned switching to this
in all but a couple of tables.
So I think they are currently a
good example
Nikolay: of a project that
Michael: has both.
Nikolay: You mean switching to
JSON B Shadow Table?
Michael: Yes, instead of you calling
it in place.
I think they still implement in
place in a couple of places.
Nikolay: The best thing about this
single shadow table with JSON-B
colon is that it's so easy to attach
it to any table.
It's just a trigger.
That's it.
It will slow down, delete a little
bit.
That's it.
Michael: Yeah, because of the triggers.
You could use it for the hard delete
and then have it for around
for a while longer.
Nikolay: We discussed about compliance
and so on, but, and I
mentioned that for business owners,
like there are fears that
like something was deleted, hard
to recover.
It's very good for audit purposes.
For example, you have some account
in your application, and there
are some admins, or like owners,
managers, and there are some
regular users.
Some users do something, they deleted
something, and you just
need to not only see and undo it
but see when it was done by
whom like
Michael: I saw another person in
a hacker news thread talk.
Yeah.
Not just audit but also what really
happened.
So I saw somebody who had implemented
a chat system.
Let's say it's a support business
to business support system
and 1 of your internal works for
your company users said something
they regret saying as part of this
chat and then deleted 1 of
those messages.
It's really useful for an admin
to see the whole history or you
know, you mentioned social media
and a lot of social media sites
that you edit a message, keeping
the old version.
I edited
Nikolay: this update, not delete.
So this leads us to like time travel
basically.
We cannot say, name it soft updates,
right?
But tracking all versions, it actually
also possible they are
the same approach.
And I think I did it as well.
So when you have delete with this
trigger with security, security,
definer function, trigger function,
which just archives previous
record.
In the trigger function, you use
old key name.
This is just record, right?
And you convert it to JSONB and
insert, right?
Absolutely the same trigger can
be used for updates.
With any update, maybe I would
have some checks if some actual
data was changed, not just something
small was changed, right?
But actual data, like message was
changed, right?
Title, message.
New dot title doesn't equal old
dot title, and so on.
If something, just to avoid, you
know, like spam archiving, which
like useless records in this shadow
table.
So if I see something valuable
has been changed with this update,
again, I back old to JSONB and
sort the same, like the same trigger
basically.
Right?
Michael: Yeah, I'm not sure.
It depends.
It depends how and when you need,
how often you need to be viewing
those older ones, because it might
be tricky to show the admin
those if you, how are you going
to select that data back out
to show them the old versions?
I guess it's tricky.
Nikolay: I would, by the way, no,
for updates, I think This is
what I did actually.
For updates, I would archive probably
both old and new records.
Because just, yes, to be able to
show diff.
Yes, it's like too much data to
store, but why not?
In this case, I would extend shadow
table with additional JSONB
column.
Like, delete...
Records related to deletes won't
have it.
Like, they would have only nulls
in that column.
For updates, I would have 2 JSONB
values.
Michael: Interesting.
Nikolay: Old and new, basically.
And then we can build some diff
if needed.
Right?
Michael: Maybe.
I think this is getting beyond
the scope of what...
But this is interesting.
I think my...
Nikolay: No, it's useful and easy
to implement and super universal.
You can again attach it to any
table and have simple audit like
that.
Michael: But what I don't like
or understand is because this
is a single shadow table across
multiple, what are you querying?
Like, how are you looking for that
in a, let's say it was a month
ago, in your, how you're efficiently
finding that in that shadow
table?
What are you searching by?
Nikolay: Well, depending on the
application, right?
I would probably in this shadow
table, I would probably have
some columns which would allow
me to search faster, or I would
deal with searching inside JSON-B.
Why not?
Genetics?
Michael: Well, yeah, maybe.
This slows down updates.
Yeah, there's a lot of...
I think that it's a tricky one because
if it's a shadow table for
all tables, you'd like having user
ID or like having other columns
that you could search by might
not make sense for some of those.
Nikolay: You can have null there.
Michael: True, true, true.
Nikolay: Well, yeah, I agree with
that.
Especially if you add gin, insert
this implicit insert, which
happens during delete or update,
it will be not fast at all because
of gin.
So yeah, overhead.
This is the price.
You have it.
Michael: Yeah, I like that.
It's another trade-off.
It depends what you want, and it
depends how much data you have,
and it depends what proportion
is ever going to be deleted, or
what proportion is ever going to
be restored or looked into.
But yeah, I think it's really cool.
I'll link up the blog post we mentioned.
Any last things you wanted to add?
Nikolay: Actually you know what,
during this discussion, I was
curious what we have in PostgreSQL
system and actually we have
exactly this approach I just described.
We have a shadow table, single
one for many tables to track deletes
and updates.
It's called audit log and we have
data before and data after
2 JSONB columns.
Michael: Interesting.
Yeah,
Nikolay: and actually a lot of
additional stuff.
This is just to be able to show
admins of organizations what
happened.
Michael: In pgMustard, we have hard
deletes.
It's slightly different because
it's just query plans, right?
And you can always submit them
again.
But if you delete them, they're
gone.
So we decided not to at all.
Nikolay: Yeah, and now an application
cannot reach this part
of database at all.
It's only possible like implicitly,
as I described, via security
definers.
So quite a good approach, very
reliable.
Michael: Yeah.
Nice.
All right.
Well, thanks so much, Nikolay.
Catch you
Nikolay: next week.
Thank you.
Good chat.