1
00:00:00,060 --> 00:00:03,680
Nikolay: Hello, hello, this is
PostgresFM, podcast about PostgreSQL.
2
00:00:04,920 --> 00:00:06,540
Do I pronounce it right, Michael?
3
00:00:06,660 --> 00:00:07,580
Michael: I think so.
4
00:00:07,840 --> 00:00:08,140
Nikolay: Yeah.
5
00:00:08,140 --> 00:00:09,100
And hi, Michael.
6
00:00:09,340 --> 00:00:10,420
Michael from pgMustard.
7
00:00:11,600 --> 00:00:12,640
Michael: Hello, Nikolay.
8
00:00:12,640 --> 00:00:15,340
Nikolay: Yeah, and I'm Nikolay,
Postgres.AI.
9
00:00:15,340 --> 00:00:16,520
And let's...
10
00:00:16,860 --> 00:00:18,920
We don't have guests today, unfortunately.
11
00:00:19,540 --> 00:00:22,720
We have good guests coming soon,
but not this time.
12
00:00:24,240 --> 00:00:28,440
My idea was, you know how much
I don't like to deal with security.
13
00:00:28,660 --> 00:00:30,560
I just need to do it.
14
00:00:31,260 --> 00:00:34,500
Let's talk about policies, create
policy.
15
00:00:35,500 --> 00:00:37,520
Why is it create policy, by the
way?
16
00:00:37,540 --> 00:00:41,140
It's not create RLS policy, it's
just create policy.
17
00:00:42,260 --> 00:00:45,280
Policy is a very general word,
right?
18
00:00:45,280 --> 00:00:49,700
It can be not only row level security,
maybe some other policies.
19
00:00:50,660 --> 00:00:53,540
Do you think the decision was made
to...
20
00:00:54,140 --> 00:00:55,540
I think this is not standard.
21
00:00:55,840 --> 00:00:59,920
I'm not sure because I just checked
with some AI and it says
22
00:01:00,060 --> 00:01:02,820
SQL standard doesn't have RLS.
23
00:01:03,620 --> 00:01:06,160
Michael: I looked up where did
the name come from because it
24
00:01:06,160 --> 00:01:09,060
wasn't the title of the page in
the Postgres documentation.
25
00:01:10,440 --> 00:01:13,100
And the time it's used is in the
alter table statement.
26
00:01:13,100 --> 00:01:16,320
So this is a table level setting
that you first enable.
27
00:01:16,560 --> 00:01:20,100
And only once you've enabled it
on the table, then you set policies.
28
00:01:20,660 --> 00:01:25,520
So it's alter table, and then enable
row level security, and
29
00:01:25,520 --> 00:01:29,700
then once that's enabled, you need
to create at least 1 policy
30
00:01:29,700 --> 00:01:32,860
so that people, or non-superusers,
can read anything.
31
00:01:33,260 --> 00:01:37,120
Nikolay: Right, but still, it confused
me from the very beginning.
32
00:01:37,120 --> 00:01:41,180
I think it was implemented originally
very long ago, right, before
33
00:01:41,320 --> 00:01:44,020
Postgres 10 or after, I don't remember.
34
00:01:44,020 --> 00:01:45,560
Michael: I didn't actually check
this time.
35
00:01:45,600 --> 00:01:48,540
Nikolay: Yeah, but I think it's
quite old feature relatively.
36
00:01:50,140 --> 00:01:55,760
It definitely wasn't in Postgres
9.0, but possibly it's already
37
00:01:55,760 --> 00:01:56,620
present in...
38
00:01:57,040 --> 00:01:58,280
Michael: I found it in 9.5.
39
00:01:58,780 --> 00:02:00,040
Nikolay: 9.5, yeah.
40
00:02:00,240 --> 00:02:02,960
It means 2015 or something, right?
41
00:02:03,900 --> 00:02:09,060
So let's talk about the problem
it's solving or tries to solve.
42
00:02:09,400 --> 00:02:15,400
Problem is in the era of SaaS,
software as a service, We have
43
00:02:15,400 --> 00:02:21,340
a lot of cases when 1 system running
in cloud operates with many,
44
00:02:21,340 --> 00:02:30,860
many different users which ideally
should not put at risk each
45
00:02:30,860 --> 00:02:31,860
other or something.
46
00:02:32,120 --> 00:02:33,300
There should be some segregation.
47
00:02:33,540 --> 00:02:37,600
For example, if we have, say, like
Twitter style, right?
48
00:02:37,600 --> 00:02:39,520
We have users, we have...
49
00:02:39,900 --> 00:02:41,200
No, Twitter is not good.
50
00:02:41,200 --> 00:02:44,020
Let's think about something more
business-oriented.
51
00:02:44,460 --> 00:02:45,300
It will be more...
52
00:02:45,300 --> 00:02:48,840
Michael: Or e-commerce, being able
to see somebody else's orders
53
00:02:48,840 --> 00:02:51,700
or being able to see their address
or something like that.
54
00:02:51,880 --> 00:02:55,960
Nikolay: Let's find some B2B example
because this is where it
55
00:02:55,960 --> 00:02:59,960
feels much more sound, so to speak.
56
00:02:59,960 --> 00:03:03,980
So, for example, let's take Slack
and we try to implement Slack,
57
00:03:04,000 --> 00:03:04,500
right?
58
00:03:05,280 --> 00:03:10,380
So we have workspaces, many of
them, and channels inside and
59
00:03:10,380 --> 00:03:14,060
people communicate, but each workspace
belongs to some customer,
60
00:03:14,060 --> 00:03:16,340
some organization which uses our
service.
61
00:03:16,480 --> 00:03:17,700
And it's SaaS, right?
62
00:03:17,800 --> 00:03:18,660
It's in cloud.
63
00:03:19,180 --> 00:03:23,480
And is it a good idea to keep all
messages, for example, in a
64
00:03:23,480 --> 00:03:27,240
single, maybe partition, but we
forget about performance for
65
00:03:27,240 --> 00:03:32,840
a while, in a single table called
like messages for all customers?
66
00:03:33,680 --> 00:03:35,900
Maybe it's a good idea, maybe not,
right?
67
00:03:35,900 --> 00:03:41,620
But from security point of view,
it's terrible idea because if
68
00:03:41,880 --> 00:03:48,120
selecting our messages, we have
some bug or some kind of hacker
69
00:03:48,120 --> 00:03:52,860
attack, we can select other organization
messages, right?
70
00:03:53,560 --> 00:03:54,520
And that's bad.
71
00:03:55,080 --> 00:04:00,660
So, or maybe just developer forgot
to put some condition, again,
72
00:04:00,660 --> 00:04:03,140
a bug or something like unintentional.
73
00:04:04,280 --> 00:04:09,100
And suddenly 1 organization deals
with messages from other organizations.
74
00:04:09,720 --> 00:04:11,880
It sounds super scary, right?
75
00:04:13,660 --> 00:04:17,140
For platform development, I mean
for the SaaS service developers,
76
00:04:17,360 --> 00:04:18,220
it's bad.
77
00:04:18,960 --> 00:04:23,940
So my point is, some SaaS systems
still have this situation.
78
00:04:24,620 --> 00:04:27,320
Old ones definitely have this situation
unresolved.
79
00:04:28,680 --> 00:04:28,780
And
80
00:04:28,780 --> 00:04:29,280
Michael: most.
81
00:04:30,040 --> 00:04:30,360
I think
82
00:04:30,360 --> 00:04:30,600
Nikolay: it
83
00:04:30,600 --> 00:04:32,180
Michael: might be most, yeah.
84
00:04:32,780 --> 00:04:35,900
Nikolay: Yeah, ultimate, so it's
called multi-tenant system,
85
00:04:35,900 --> 00:04:36,400
right?
86
00:04:37,280 --> 00:04:42,040
Ultimate way is like you create
a database or maybe it's like
87
00:04:42,100 --> 00:04:46,820
whole cluster for each, at least
big customer and that's it,
88
00:04:46,820 --> 00:04:47,320
right?
89
00:04:47,400 --> 00:04:51,160
And full segregation, full separation
of data, and that's great,
90
00:04:51,160 --> 00:04:52,700
but it's super expensive.
91
00:04:53,300 --> 00:04:58,080
Even if you put it in the same
database, in the same schema,
92
00:04:58,080 --> 00:05:01,200
but in different tables, it's also
quite expensive.
93
00:05:01,560 --> 00:05:04,900
Although we know Postgres can live
with millions of tables.
94
00:05:05,540 --> 00:05:10,160
I can send you a new Presentation
we just recently discussed
95
00:05:10,160 --> 00:05:12,720
it wasn't probably Presented in
Brazil.
96
00:05:12,720 --> 00:05:15,280
I don't remember again like hundred
million tables.
97
00:05:15,280 --> 00:05:15,940
Is it possible?
98
00:05:15,940 --> 00:05:20,040
Well, it's possible, but it's difficult.
99
00:05:20,660 --> 00:05:24,360
So the idea of RLS comes from this
problem.
100
00:05:24,480 --> 00:05:29,360
We want to have guaranteed protection
that 1 customer sees only
101
00:05:29,640 --> 00:05:32,680
their data, not other customers' data.
102
00:05:32,680 --> 00:05:37,860
And it can be achieved by defining special rule that additional
103
00:05:39,020 --> 00:05:43,140
condition will be always present in selects right or updates
104
00:05:43,140 --> 00:05:44,560
deletes inserts
105
00:05:44,600 --> 00:05:47,580
Michael: yeah and I think I think would you say it's fair that
106
00:05:47,680 --> 00:05:51,100
most, when I said most don't have this, I mean most don't have
107
00:05:51,100 --> 00:05:52,360
it at the database level.
108
00:05:52,360 --> 00:05:55,580
I think most people put a lot of effort into making sure this
109
00:05:55,580 --> 00:05:59,820
couldn't happen at the application level, but most don't also
110
00:05:59,860 --> 00:06:03,420
add an additional level, like layer of defense at the database
111
00:06:03,420 --> 00:06:03,640
level.
112
00:06:03,640 --> 00:06:06,780
And this is a database level, so any application sitting on top
113
00:06:06,780 --> 00:06:10,140
of it, or any client sitting on top of it, gets that by default.
114
00:06:10,420 --> 00:06:13,220
Nikolay: Yeah, that's why I always say we cannot trust the application
115
00:06:13,480 --> 00:06:17,120
layer, because what if next year your organization decides to
116
00:06:17,120 --> 00:06:20,140
try a new framework or something and you have 2 applications
117
00:06:20,320 --> 00:06:23,040
and they behave differently or you need to deal with implementing
118
00:06:23,040 --> 00:06:25,880
the same rules in 2 systems and basically copy-pasting.
119
00:06:26,880 --> 00:06:30,040
Sometimes in different languages it's super hard to maintain.
120
00:06:30,880 --> 00:06:35,440
What if you have some specific interfaces connected to database
121
00:06:35,440 --> 00:06:39,880
and people just work with this data directly, right?
122
00:06:40,840 --> 00:06:43,460
They bypass your application logic completely.
123
00:06:45,480 --> 00:06:49,240
This is good to have inside the database, closer to data, and
124
00:06:49,340 --> 00:06:51,380
applied in the same manner to all.
125
00:06:51,580 --> 00:06:55,140
I wanted to say this problem can be solved using views.
126
00:06:57,260 --> 00:07:01,720
So you can, for example, have a view which will deal only with
127
00:07:01,720 --> 00:07:07,660
data dynamically for a particular customer only, not seeing anything
128
00:07:07,660 --> 00:07:08,160
else.
129
00:07:08,680 --> 00:07:13,880
You just put something to the rule definition, which will involve
130
00:07:14,140 --> 00:07:16,120
some current setting again.
131
00:07:16,880 --> 00:07:20,000
And in the current setting you have your customer ID, for example,
132
00:07:20,000 --> 00:07:25,700
and you say, okay, this view is selecting rows from messages
133
00:07:25,800 --> 00:07:30,780
table, where, and we have the check that customer, like project
134
00:07:30,780 --> 00:07:34,020
ID, organization ID, doesn't matter, it belongs to this customer
135
00:07:34,020 --> 00:07:34,960
ID, that's it.
136
00:07:34,960 --> 00:07:35,420
Always.
137
00:07:35,420 --> 00:07:36,800
It can be joined maybe.
138
00:07:37,280 --> 00:07:41,780
And in this case, this view can be even writable, so inserts,
139
00:07:41,780 --> 00:07:43,220
deletes, updates could work.
140
00:07:43,900 --> 00:07:46,680
And this check is automatically verified.
141
00:07:47,060 --> 00:07:49,280
Although maybe it's not verified at insert time.
142
00:07:49,280 --> 00:07:50,280
I don't remember exactly.
143
00:07:50,280 --> 00:07:52,100
I think there is some caveat here.
144
00:07:54,520 --> 00:07:58,140
But if we think about only selects at least, it's definitely
145
00:07:58,140 --> 00:07:58,640
working.
146
00:08:00,060 --> 00:08:03,680
If you make your application work only with this view, not with
147
00:08:03,680 --> 00:08:09,060
the original underlying table, in this case you can be 100% sure
148
00:08:09,060 --> 00:08:13,960
that they will see only data they can see, not anything else.
149
00:08:15,740 --> 00:08:19,240
This additional filter will be always—planner will be always
150
00:08:19,240 --> 00:08:20,060
using it.
151
00:08:20,580 --> 00:08:23,800
But this is not RLS, it's an alternative
approach.
152
00:08:23,860 --> 00:08:25,380
And I think inserts will be a problem.
153
00:08:25,380 --> 00:08:29,540
I don't remember 100%, but I remember
I was, I got bitten by
154
00:08:29,540 --> 00:08:34,200
this problem a few times in my
experience, and we needed to implement
155
00:08:34,200 --> 00:08:37,440
triggers to double-check that inserts
are protected and the same
156
00:08:37,440 --> 00:08:39,780
rule is applied the third time.
157
00:08:40,020 --> 00:08:42,940
So maybe this is like downside
of this approach.
158
00:08:43,940 --> 00:08:51,160
But create policy statement is
more like natural way to protect
159
00:08:51,180 --> 00:08:52,740
data for these purposes, right?
160
00:08:52,740 --> 00:08:59,580
So we define a policy and we alter
a table saying that row level
161
00:08:59,620 --> 00:09:01,420
security is enabled for this table.
162
00:09:01,420 --> 00:09:02,700
By default, it's not, right?
163
00:09:02,800 --> 00:09:04,580
Michael: Well, yeah, in Postgres,
yeah.
164
00:09:04,840 --> 00:09:08,040
Nikolay: Yeah, and then this policy
is supposed to protect us
165
00:09:08,080 --> 00:09:12,940
in terms of multi-tenant situations,
so customers deal only with
166
00:09:12,940 --> 00:09:15,640
the data they can deal with, they
don't see each other.
167
00:09:15,940 --> 00:09:19,060
Do you think it's a good protection
for multi-tenant situation
168
00:09:19,940 --> 00:09:21,900
when we keep everything in 1 table?
169
00:09:22,200 --> 00:09:24,400
Michael: I have mixed feelings
about role of security.
170
00:09:24,520 --> 00:09:28,340
I think this is a security question
in general.
171
00:09:28,820 --> 00:09:31,820
How much are the downsides worth
it?
172
00:09:31,820 --> 00:09:34,840
How much is the extra complexity
worth it for the additional
173
00:09:34,840 --> 00:09:41,100
security and yeah I think in environments
where security is of
174
00:09:41,100 --> 00:09:45,100
paramount importance it makes sense
to add security at every
175
00:09:45,100 --> 00:09:47,100
level including this
176
00:09:47,520 --> 00:09:50,200
Nikolay: 1 this 1 I mean you mean
database level
177
00:09:50,360 --> 00:09:53,600
Michael: yeah I don't see Postgres
very level security in use
178
00:09:53,600 --> 00:09:57,800
that much so most people seem to
be making the trade-off of not
179
00:09:57,800 --> 00:10:02,520
using it in favor well not in favor
of I suspect most people
180
00:10:02,520 --> 00:10:06,100
using row level Security also have
other measures in place.
181
00:10:06,660 --> 00:10:10,020
But I've seen a growing number
of performance related questions
182
00:10:10,020 --> 00:10:12,180
around Rail-Level Security in various
communities.
183
00:10:12,720 --> 00:10:18,620
And I think it's due to the popularity
of PostgREST and the
184
00:10:18,680 --> 00:10:20,840
automatic creating.
185
00:10:20,860 --> 00:10:26,000
Also, my theory is because people
are creating these RESTful
186
00:10:26,000 --> 00:10:31,780
APIs directly interfacing with
the database, it becomes super
187
00:10:31,780 --> 00:10:34,900
important to have security at the
database level because people
188
00:10:34,900 --> 00:10:36,940
can change the parameters of the
URL.
189
00:10:37,200 --> 00:10:41,080
And otherwise, they could just
view other people's data immediately.
190
00:10:41,580 --> 00:10:44,620
So I think it makes sense that
it's growing in popularity.
191
00:10:44,620 --> 00:10:47,320
But I don't think it's been growing
in popularity as an additional
192
00:10:47,360 --> 00:10:47,640
layer.
193
00:10:47,640 --> 00:10:50,640
I think it's been growing in popularity
as the only layer.
194
00:10:50,660 --> 00:10:51,660
But I could be wrong.
195
00:10:51,660 --> 00:10:54,900
Nikolay: Yeah, that's interesting,
because exactly this alternative
196
00:10:54,920 --> 00:10:58,220
approach, which I explained using
views, it's coming.
197
00:10:59,060 --> 00:11:04,080
Actually, my bachelor thesis was
about updatable views, and master
198
00:11:04,080 --> 00:11:06,740
thesis was about updatable XML
views.
199
00:11:06,900 --> 00:11:09,220
So it was like 20 years plus ago.
200
00:11:09,520 --> 00:11:15,220
But Postgres particularly provokes
you to use views over tables
201
00:11:15,220 --> 00:11:15,880
and views.
202
00:11:15,880 --> 00:11:21,200
You just create a view in, say,
by default, schema v1, and this
203
00:11:21,200 --> 00:11:24,440
is your v1 version 1 API.
204
00:11:25,160 --> 00:11:31,520
By creating views and controlling
who can see what, you can already
205
00:11:31,520 --> 00:11:33,300
limit access.
206
00:11:34,460 --> 00:11:38,000
You can hide some columns, just
not taking them to views, and
207
00:11:38,000 --> 00:11:38,700
so on.
208
00:11:39,340 --> 00:11:43,380
And that's great, but maybe you
are right, because I did see
209
00:11:43,380 --> 00:11:47,940
some popularity of low-level security
growing from that side.
210
00:11:48,160 --> 00:11:52,260
Because people need more and more
and more logic on database
211
00:11:52,260 --> 00:11:56,180
side, which is related to data,
because there is no middleware.
212
00:11:56,460 --> 00:12:00,180
It's only this high-skill application
called Postgres.
213
00:12:00,940 --> 00:12:04,400
And all the data-related logic
is supposed to be in database,
214
00:12:04,600 --> 00:12:06,660
including everything related to
permissions.
215
00:12:07,720 --> 00:12:11,880
And all UI logic is on FAT client,
right?
216
00:12:11,880 --> 00:12:13,500
It's like React or something.
217
00:12:14,240 --> 00:12:16,820
And, Yeah, I see your point.
218
00:12:16,820 --> 00:12:17,320
Exactly.
219
00:12:17,320 --> 00:12:23,160
If you have middleware, Ruby, Python,
Java, anything, then people
220
00:12:23,160 --> 00:12:26,120
tend to implement all the security
checks right there, right?
221
00:12:26,120 --> 00:12:29,160
And maintain them in a unified
way and so on.
222
00:12:29,160 --> 00:12:29,940
Yeah, I agree.
223
00:12:30,100 --> 00:12:32,980
There's no application, middleware
application here.
224
00:12:32,980 --> 00:12:35,860
So it goes to database or where
else, right?
225
00:12:35,860 --> 00:12:37,480
Because it cannot go to UI.
226
00:12:37,540 --> 00:12:40,320
But interesting, again, views are
there as well, but it's not
227
00:12:40,320 --> 00:12:40,660
enough.
228
00:12:40,660 --> 00:12:42,100
It doesn't feel enough.
229
00:12:42,440 --> 00:12:46,420
And sometimes we need to deal with
data from multiple clients.
230
00:12:46,840 --> 00:12:48,080
Sometimes, it depends, right?
231
00:12:48,080 --> 00:12:50,820
Because, I mean, admin mode or
something, right?
232
00:12:51,340 --> 00:12:56,000
Yeah, in this case, ROLL security
provides this bypass RLS flag
233
00:12:56,000 --> 00:12:59,540
for when you create a role or user,
you can specify this flag,
234
00:12:59,540 --> 00:13:03,420
it's kind of super user, not super
user, but it bypasses these
235
00:13:03,420 --> 00:13:04,780
security checks, right?
236
00:13:05,140 --> 00:13:05,980
Yeah, I agree.
237
00:13:05,980 --> 00:13:10,460
And then, but my point stands as
well, like old SaaS systems,
238
00:13:10,520 --> 00:13:16,400
they tend to not using RLS, but
there are many other fresh, like
239
00:13:16,860 --> 00:13:22,200
last few years, a lot of SaaS systems
are created, have been
240
00:13:22,200 --> 00:13:27,800
created, and still created, and
also with AI, it's also very
241
00:13:27,800 --> 00:13:31,800
much standard situation sometimes
think about charge BT as well
242
00:13:31,960 --> 00:13:35,100
It's also like kind of many messages
from these chats.
243
00:13:35,280 --> 00:13:38,320
It can be also single table and
it requires some security as
244
00:13:38,320 --> 00:13:38,980
well, right?
245
00:13:39,240 --> 00:13:43,260
And my point is that new SaaS systems,
they tend to have it even
246
00:13:43,260 --> 00:13:48,160
without Postgres or Hasura or something
like that.
247
00:13:48,900 --> 00:13:55,340
Even if they use regular Django
or Java or anything, they sometimes,
248
00:13:55,380 --> 00:13:59,300
I just observed it, they sometimes
implement RLS because they
249
00:13:59,300 --> 00:14:03,620
think, okay, we need better protection
for our SaaS system.
250
00:14:05,080 --> 00:14:05,740
Multi-tenant system.
251
00:14:05,740 --> 00:14:07,480
Michael: Cool, I didn't realize that, that's great.
252
00:14:07,480 --> 00:14:10,240
Nikolay: Yeah, I just see it, and then they grow and start hitting
253
00:14:10,240 --> 00:14:11,260
performance issues.
254
00:14:13,320 --> 00:14:17,080
And this is natural, And it looks like the first, let's talk
255
00:14:17,080 --> 00:14:18,740
about performance, if you don't mind.
256
00:14:19,120 --> 00:14:21,680
Michael: No, I think the most interesting part of this
257
00:14:21,680 --> 00:14:22,360
Nikolay: is performance.
258
00:14:23,260 --> 00:14:28,180
And the first thing they bump into sometimes, not everyone, is
259
00:14:28,180 --> 00:14:33,580
that having some condition present in the RLS definition, this
260
00:14:33,800 --> 00:14:37,220
filtering, doesn't mean that the planner will see it.
261
00:14:37,360 --> 00:14:39,980
You can have an index on a column.
262
00:14:40,200 --> 00:14:41,760
For example, it's a simple condition.
263
00:14:42,040 --> 00:14:43,520
Some column equals some constant.
264
00:14:43,520 --> 00:14:47,200
Forget about current setting or some stable functions for a while.
265
00:14:47,420 --> 00:14:48,180
Some constant.
266
00:14:48,700 --> 00:14:52,920
And we have an index on this column, but we don't have this condition
267
00:14:53,700 --> 00:14:55,420
used in the where clause.
268
00:14:56,520 --> 00:14:59,600
This will lead to sequential scan, right?
269
00:14:59,600 --> 00:15:03,460
Because planner doesn't see what row level security is going
270
00:15:03,460 --> 00:15:06,400
to, which filter is going to apply, right?
271
00:15:07,100 --> 00:15:08,060
And this is surprise.
272
00:15:09,060 --> 00:15:12,260
Michael: Yeah, sequential scan, but like with a filter so each
273
00:15:12,260 --> 00:15:14,440
1 will be checked against the policy
274
00:15:16,260 --> 00:15:17,340
Nikolay: Just use it
275
00:15:18,380 --> 00:15:20,820
Michael: You might even yes, even if you have an index on that.
276
00:15:20,820 --> 00:15:24,100
So yeah, that's super unintuitive, I think, for people.
277
00:15:24,520 --> 00:15:27,300
And it tripped me up when I was reading about this.
278
00:15:27,620 --> 00:15:33,900
I thought, I wondered if it could use an index on a simple policy,
279
00:15:34,040 --> 00:15:37,620
on a column, like a user ID or something like that.
280
00:15:37,900 --> 00:15:41,680
And I even saw guides, in fact, there's a really good guide on
281
00:15:41,680 --> 00:15:45,900
row level security by the team at Supabase who heavily encourage
282
00:15:46,360 --> 00:15:51,340
the use of row level security as part of their offering because
283
00:15:51,340 --> 00:15:52,320
they're using Postgres.
284
00:15:53,080 --> 00:15:56,760
But yeah, they say you can think of policies as adding a where
285
00:15:56,760 --> 00:15:58,020
clause to every query.
286
00:15:58,520 --> 00:16:01,500
But that tripped me up When it came to performance because it's
287
00:16:01,500 --> 00:16:03,900
not like a where clause from a performance perspective.
288
00:16:03,900 --> 00:16:07,460
It's like a where clause from like a user experience perspective
289
00:16:07,540 --> 00:16:11,680
like from a from what you see at the end of the Data coming back
290
00:16:11,680 --> 00:16:14,820
might might look the same as if you'd feel today using a where
291
00:16:14,820 --> 00:16:18,040
clause But performance like the planner doesn't have access to
292
00:16:18,040 --> 00:16:21,660
that to choose to do a different type of scan at the beginning.
293
00:16:21,820 --> 00:16:26,400
So yeah, super important distinction and 1 of their tips on the
294
00:16:26,400 --> 00:16:29,600
performance side is therefore to always include all the filters
295
00:16:29,600 --> 00:16:31,900
you want anyway in the queries.
296
00:16:32,320 --> 00:16:34,800
Nikolay: Yeah Yeah, that's interesting.
297
00:16:35,240 --> 00:16:38,360
But it's easy to solve, I think.
298
00:16:38,420 --> 00:16:41,680
Just add it there, into the where class, and that's it.
299
00:16:42,340 --> 00:16:46,500
Let's talk about, step back maybe a little bit about not performance,
300
00:16:46,840 --> 00:16:50,240
because I will forget about this, but I wanted to share some
301
00:16:50,500 --> 00:16:51,820
feature stuff.
302
00:16:51,820 --> 00:16:56,840
First of all, I saw the case that
if we have foreign keys and
303
00:16:56,840 --> 00:17:01,160
so on, referential integrity checks
are not covered, right?
304
00:17:01,560 --> 00:17:06,220
This is like, like, the integrity
is more important than role
305
00:17:06,220 --> 00:17:07,540
level security, right?
306
00:17:07,740 --> 00:17:10,640
Did you see any interesting cases
related to this?
307
00:17:11,320 --> 00:17:14,660
Michael: Well, I only read about,
I thought it was a really fascinating
308
00:17:15,560 --> 00:17:20,140
concept that by enforcing referential
integrity you could be
309
00:17:20,140 --> 00:17:22,460
leaking security information like
if you...
310
00:17:22,460 --> 00:17:24,400
Nikolay: Or inserting something
which is not...
311
00:17:24,400 --> 00:17:27,100
Michael: Yeah exactly if you're
1 user trying to insert something
312
00:17:27,380 --> 00:17:33,120
and you find out that it that it
fails to be inserted then you
313
00:17:33,120 --> 00:17:35,760
know that thing exists but from
some other user.
314
00:17:35,760 --> 00:17:38,760
Nikolay: Insert is a bad example,
because foreign key doesn't
315
00:17:38,760 --> 00:17:39,340
help with insert.
316
00:17:39,340 --> 00:17:41,680
It helps with, for example, deletes,
right?
317
00:17:41,680 --> 00:17:42,840
Like, SK deletes.
318
00:17:43,480 --> 00:17:47,140
So you, for example, can delete
what you cannot see or something
319
00:17:47,140 --> 00:17:47,680
like that.
320
00:17:47,680 --> 00:17:48,900
Michael: Yeah, Yeah, sorry, good
point.
321
00:17:48,900 --> 00:17:51,800
Maybe it's not relevant then, but
I did read in the documentation
322
00:17:52,660 --> 00:17:58,780
that you need to be careful with
leaking information by checking...
323
00:18:00,060 --> 00:18:01,320
Nikolay: Ah, I see how.
324
00:18:01,320 --> 00:18:05,140
For example, if you try to delete
something without cascade and
325
00:18:05,140 --> 00:18:09,380
it says it cannot be deleted because
there is a row in different
326
00:18:09,380 --> 00:18:14,240
table which we reference to, it
reveals the presence of this
327
00:18:14,240 --> 00:18:17,060
row, but maybe you are not supposed
to see it.
328
00:18:18,760 --> 00:18:20,780
Yeah, you like, it's not your role.
329
00:18:21,100 --> 00:18:23,180
It's somebody else's role.
330
00:18:23,680 --> 00:18:24,920
Something like this, interesting.
331
00:18:24,920 --> 00:18:27,980
Yeah, and then like from error,
you can conclude that there is
332
00:18:27,980 --> 00:18:30,040
some data there, right?
333
00:18:30,100 --> 00:18:32,620
Maybe you can understand the values.
334
00:18:32,980 --> 00:18:33,980
Yeah, it's interesting.
335
00:18:34,120 --> 00:18:36,880
But I never saw such situations
in production.
336
00:18:37,540 --> 00:18:41,860
Another thing I had experience
with is that pg_dump.
337
00:18:42,340 --> 00:18:46,460
Yeah, you mentioned also before
we started recording that it's
338
00:18:46,460 --> 00:18:47,380
bad for backups.
339
00:18:48,580 --> 00:18:52,620
Michael: No, it's not bad, but
you just have to test your backups.
340
00:18:53,200 --> 00:18:55,580
Nikolay: But as I said, the dumps
are not backups.
341
00:18:56,280 --> 00:19:00,600
I'm still on this idea that by
default backup is physical backup.
342
00:19:00,600 --> 00:19:02,580
If we say logical backups, okay.
343
00:19:03,200 --> 00:19:06,560
It's good, it's bad for, I mean
not bad, exactly.
344
00:19:06,620 --> 00:19:11,960
It can be tricky and surprising
for logical backups.
345
00:19:11,960 --> 00:19:16,480
For example, you dump your table
but you see only rows you can
346
00:19:16,480 --> 00:19:16,980
see.
347
00:19:17,520 --> 00:19:18,020
Surprise.
348
00:19:18,240 --> 00:19:19,860
Michael: Yeah, well, exactly.
349
00:19:19,860 --> 00:19:23,320
I was just imagining using a service
like Supabase and wanting
350
00:19:23,320 --> 00:19:29,340
to keep a semi-regular dump of
the data somewhere else just for
351
00:19:29,340 --> 00:19:30,920
my own peace of mind.
352
00:19:31,320 --> 00:19:34,900
Nikolay: No errors, just lack of
a lot of data.
353
00:19:38,100 --> 00:19:41,680
Michael: It was more that if you're
not super careful about which
354
00:19:41,680 --> 00:19:44,800
user you're using, like making
sure that's from a super user
355
00:19:44,800 --> 00:19:49,540
or some role that can see all the
data, it'd be very easy to
356
00:19:49,540 --> 00:19:53,940
think I've got like I've backed
this up and then if you actually
357
00:19:53,940 --> 00:19:57,020
ever need it you're in real trouble
you've lost a lot of data.
358
00:19:57,180 --> 00:19:59,560
Nikolay: Yeah you can have it unnoticed.
359
00:20:00,540 --> 00:20:04,120
Michael: Yeah a credit to the Postgres
documentation They called
360
00:20:04,120 --> 00:20:06,100
that out as something to be aware
of.
361
00:20:06,500 --> 00:20:11,240
Nikolay: In the same area of dumps,
a pg_dump doesn't have skip
362
00:20:11,240 --> 00:20:14,820
policies, or pg_restore doesn't
have skip policies flag, as I
363
00:20:14,820 --> 00:20:15,320
remember.
364
00:20:16,060 --> 00:20:20,360
And this was a problem because
some users of our Database Lab
365
00:20:20,360 --> 00:20:23,100
Engine, DBLab Engine, they...
366
00:20:23,640 --> 00:20:26,920
This is how actually I noticed
that more and more people start
367
00:20:26,920 --> 00:20:28,940
using row level security.
368
00:20:29,480 --> 00:20:32,900
I just like They start asking questions,
okay, we have some low-level
369
00:20:32,900 --> 00:20:36,860
security here, but we restore it
under, like in this non-production
370
00:20:37,080 --> 00:20:39,740
environment for dev test activities.
371
00:20:40,440 --> 00:20:43,940
And we don't need row level security
at all here, right?
372
00:20:44,160 --> 00:20:45,040
How to skip it?
373
00:20:45,040 --> 00:20:48,300
We just want to check various stuff.
374
00:20:49,940 --> 00:20:53,940
And pg_restore has a lot of flags,
to skip this, to skip that,
375
00:20:53,940 --> 00:20:54,740
many things.
376
00:20:55,400 --> 00:20:59,420
But as for policies, skip policies,
it's lacking.
377
00:20:59,700 --> 00:21:05,440
And We needed to deal with feature
supports, hyphen l, small
378
00:21:05,440 --> 00:21:10,440
l, lowercase l and uppercase L,
to have a list of objects present
379
00:21:10,440 --> 00:21:15,860
in the dump, and then just have
filter added, like it's a dictionary
380
00:21:15,920 --> 00:21:19,780
of everything that was dumped,
and we just removed policies and
381
00:21:19,780 --> 00:21:21,220
then restored without them.
382
00:21:21,220 --> 00:21:23,800
And we automated this in the Database
Lab Engine.
383
00:21:23,860 --> 00:21:27,520
So basically, the idea is, if I
had a little bit more time, I
384
00:21:27,520 --> 00:21:30,060
would probably code it and pg_restore
could have it.
385
00:21:30,060 --> 00:21:33,360
It feels like some good addition
for future Postgres versions.
386
00:21:34,060 --> 00:21:38,080
Michael: I understand the attraction,
but I'm also kind of against
387
00:21:38,140 --> 00:21:38,480
it.
388
00:21:38,480 --> 00:21:41,480
Like, partly because we're about
to discuss performance issues,
389
00:21:41,480 --> 00:21:41,980
right?
390
00:21:42,260 --> 00:21:44,020
I'd want to catch those earlier.
391
00:21:44,040 --> 00:21:45,260
I'd want to know.
392
00:21:45,360 --> 00:21:49,600
I'd probably want to still have
row level security on in my dev
393
00:21:49,600 --> 00:21:50,100
environment.
394
00:21:52,040 --> 00:21:53,040
Nikolay: Good point, actually.
395
00:21:53,220 --> 00:21:53,720
Yeah.
396
00:21:54,000 --> 00:21:57,360
Removing policies, this is what
we didn't think about.
397
00:21:57,360 --> 00:22:01,740
We just received idea, let's remove
it, and we implemented it.
398
00:22:01,740 --> 00:22:03,900
Now I think, oh, indeed, you're
right.
399
00:22:04,360 --> 00:22:04,980
You can...
400
00:22:05,900 --> 00:22:07,120
You don't see the whole...
401
00:22:07,200 --> 00:22:11,380
Not plan, but all the problems
that policies can bring and we
402
00:22:11,380 --> 00:22:16,740
will discuss in a minute Maybe
1 of the biggest right about stable
403
00:22:16,740 --> 00:22:21,260
function and so on Yeah, so it's
a good point But it means also
404
00:22:21,260 --> 00:22:25,760
that if you want to have policies,
you want to reconstruct your
405
00:22:25,760 --> 00:22:26,260
users.
406
00:22:26,480 --> 00:22:28,860
Well, this is a good idea as well.
407
00:22:28,860 --> 00:22:31,800
So I have 2 do ideas, 2 to do ideas.
408
00:22:32,520 --> 00:22:35,060
Anyway, skip policies is valid
flag for pg_dump.
409
00:22:35,280 --> 00:22:37,580
In some cases, it's up to the user,
right?
410
00:22:37,580 --> 00:22:39,360
It should be possible to decide.
411
00:22:39,620 --> 00:22:43,600
Because it supports the removal
of skipping of many other things.
412
00:22:44,020 --> 00:22:44,520
True.
413
00:22:44,760 --> 00:22:47,040
Like permissions, for example,
ACL, right?
414
00:22:47,040 --> 00:22:48,980
It's booming, it's skipped.
415
00:22:49,940 --> 00:22:52,620
But ownership, but RLS now.
416
00:22:52,900 --> 00:22:56,780
But I have to do for Database Lab
Engine as well, like we should find
417
00:22:56,780 --> 00:23:02,840
a path to simplify restoration
of users and to preserve all policies
418
00:23:02,980 --> 00:23:04,460
so we see performance.
419
00:23:04,620 --> 00:23:08,300
I mean, this is 1 of the purposes
of the Database Lab Engine, to experiment
420
00:23:08,420 --> 00:23:09,620
with plans, right?
421
00:23:09,620 --> 00:23:13,280
And see how indexes help or not
help, and so on.
422
00:23:13,280 --> 00:23:13,780
Yeah.
423
00:23:13,940 --> 00:23:14,440
Good.
424
00:23:15,040 --> 00:23:16,900
Let's talk about performance, back
to performance.
425
00:23:17,320 --> 00:23:23,720
So we discussed that you must put
this filter from policies.
426
00:23:23,860 --> 00:23:29,200
You must duplicate filtering in
the where clause to achieve good
427
00:23:29,200 --> 00:23:29,700
performance.
428
00:23:30,400 --> 00:23:35,320
Another thing is that it's natural
to use function current_setting,
429
00:23:35,320 --> 00:23:36,790
for example, or something like
this.
430
00:23:36,790 --> 00:23:42,180
Some function which current_setting
is just getting the value
431
00:23:42,180 --> 00:23:44,160
of a variable.
432
00:23:44,240 --> 00:23:50,680
It can be standard GUC, grand unified
configuration, or GUC variables,
433
00:23:50,740 --> 00:23:50,940
right?
434
00:23:50,940 --> 00:23:52,060
Let's call them variables.
435
00:23:52,480 --> 00:23:54,440
Or it can be user defined variable.
436
00:23:54,600 --> 00:23:58,940
It has to have namespace or blah,
blah, dot blah, blah, right?
437
00:23:59,180 --> 00:24:02,640
And you can use in set or set_config
function.
438
00:24:03,040 --> 00:24:04,660
You can set it to something.
439
00:24:05,420 --> 00:24:09,380
And then you can use it, you can
access it either using show,
440
00:24:09,520 --> 00:24:13,680
but you cannot use show inside
SQL query.
441
00:24:13,940 --> 00:24:18,500
To access it inside SQL query,
you can use function current_setting.
442
00:24:19,300 --> 00:24:24,520
And naturally for Postgres, Postgres,
and I think for Hasura
443
00:24:24,520 --> 00:24:28,020
as well, many things are coming
inside these functions already
444
00:24:28,020 --> 00:24:33,500
preset by this thin layer which
provides API.
445
00:24:33,840 --> 00:24:35,780
For example, some headers are there.
446
00:24:36,420 --> 00:24:41,820
And in headers, and also like processing
of JWT tokens, basically,
447
00:24:42,620 --> 00:24:46,220
authentication, authorization is
done through this mechanism.
448
00:24:46,240 --> 00:24:50,980
And it's natural for you to include
it into queries and say,
449
00:24:50,980 --> 00:24:53,900
okay, current_setting and blah,
blah, blah, and we see which
450
00:24:53,900 --> 00:24:57,540
user is working right now.
451
00:25:00,020 --> 00:25:03,740
And Again, it's natural to put the current setting into definition
452
00:25:04,700 --> 00:25:06,780
of your level security policies.
453
00:25:07,360 --> 00:25:13,220
And you say, okay, I don't like customer ID equals what you have
454
00:25:13,340 --> 00:25:17,360
in some headers or something coming from JWT token, anywhere.
455
00:25:17,580 --> 00:25:21,340
And you just use current setting to identify your user and Apply
456
00:25:21,340 --> 00:25:24,560
the security rule to filter out on the rows.
457
00:25:24,640 --> 00:25:29,860
This user can see only right So you have current setting used
458
00:25:29,860 --> 00:25:32,860
in row level security And here we come to 2 problems.
459
00:25:32,960 --> 00:25:36,520
First problem is 2 separate problems, actually, but they are
460
00:25:36,520 --> 00:25:37,020
connected.
461
00:25:38,300 --> 00:25:41,920
First big problem is that if you have select count dealing with
462
00:25:41,920 --> 00:25:46,160
many, many rows, like a million, 10 million, or it may be another
463
00:25:46,160 --> 00:25:46,660
aggregate.
464
00:25:47,020 --> 00:25:49,080
We know Postgres has slow count, right?
465
00:25:49,240 --> 00:25:53,620
But if you have row level security, slow count is order of magnitude
466
00:25:53,620 --> 00:25:59,340
slower, even worse, because row level security check is applied
467
00:25:59,340 --> 00:26:00,220
to each row.
468
00:26:00,940 --> 00:26:01,800
This is terrible.
469
00:26:02,080 --> 00:26:07,760
We already have very slow aggregates, which makes you think even
470
00:26:07,760 --> 00:26:13,200
more about something like materialized views or continuous aggregates
471
00:26:13,520 --> 00:26:18,740
in TimescaleDB or some other stuff, like other kind of pre-calculation,
472
00:26:20,660 --> 00:26:22,260
like denormalization with pre-calculation.
473
00:26:22,440 --> 00:26:24,100
I don't know, like something like this.
474
00:26:24,400 --> 00:26:30,360
So not providing actual values in real time, because It's a huge
475
00:26:30,360 --> 00:26:34,360
penalty, additional check, even if it's just a simple check with
476
00:26:34,360 --> 00:26:35,820
constants and that's it.
477
00:26:36,220 --> 00:26:38,040
This is the number 1 problem.
478
00:26:38,800 --> 00:26:40,900
It feels terrible and I don't have a solution.
479
00:26:40,900 --> 00:26:43,980
We don't have good solutions, actually, honestly, to slow count
480
00:26:43,980 --> 00:26:46,080
in Postgres because it's a row store.
481
00:26:46,520 --> 00:26:51,880
It's really expensive to calculate the sum of 100 million values.
482
00:26:52,860 --> 00:26:56,260
But now we all additionally need to check every row.
483
00:26:57,180 --> 00:26:58,180
Can we deal with it?
484
00:26:58,180 --> 00:26:59,120
Can we deal with it?
485
00:26:59,120 --> 00:27:00,460
Oh, it's not our row.
486
00:27:00,580 --> 00:27:02,060
Wow, it's super slow.
487
00:27:02,440 --> 00:27:07,180
But additionally, another layer of penalty comes if you use a
488
00:27:07,180 --> 00:27:11,660
function which is not immutable, which is stable, for example,
489
00:27:11,660 --> 00:27:13,280
or volatile, which is worse.
490
00:27:13,680 --> 00:27:15,600
But current setting is stable function.
491
00:27:16,780 --> 00:27:21,720
It means that Postgres also, even with its current setting and
492
00:27:21,720 --> 00:27:27,160
just some variable which is just set and that's it, it will call
493
00:27:27,160 --> 00:27:28,440
it for each row.
494
00:27:28,700 --> 00:27:29,880
Boom, boom, boom.
495
00:27:29,900 --> 00:27:30,400
Right?
496
00:27:31,260 --> 00:27:33,160
And this is insanely slow already.
497
00:27:33,340 --> 00:27:34,300
Insanely slow.
498
00:27:36,200 --> 00:27:40,120
So people can think Postgres has slow count.
499
00:27:40,920 --> 00:27:43,940
People with RLS can think, oh, it's very slow count.
500
00:27:43,940 --> 00:27:48,940
People with RLS and current setting inside RLS think, okay, it's
501
00:27:48,940 --> 00:27:49,840
terribly slow.
502
00:27:49,840 --> 00:27:51,420
Absolutely terribly slow, right?
503
00:27:52,120 --> 00:27:56,320
Yeah, but for this last problem
with current_setting, there is
504
00:27:56,320 --> 00:28:00,520
a few ways to avoid this behavior.
505
00:28:02,020 --> 00:28:07,540
I like the way just to put it inside
parentheses and write SELECT
506
00:28:07,540 --> 00:28:08,040
word.
507
00:28:08,400 --> 00:28:14,340
So Postgres Planner moves current_setting call into, it's called
508
00:28:14,340 --> 00:28:17,420
init plan, right?
509
00:28:18,180 --> 00:28:22,120
Another node in the plan, and it
will be called once, and then
510
00:28:22,120 --> 00:28:22,840
just used.
511
00:28:22,840 --> 00:28:23,580
That's great.
512
00:28:23,680 --> 00:28:25,020
So this is easy solution.
513
00:28:25,600 --> 00:28:27,600
Just surround by parentheses and...
514
00:28:28,740 --> 00:28:30,920
Just surrounded by parentheses
won't solve it.
515
00:28:30,920 --> 00:28:32,300
You need the word SELECT.
516
00:28:32,360 --> 00:28:35,380
So it becomes sub SELECT that goes
to a new plan.
517
00:28:35,380 --> 00:28:36,960
This is also interesting behavior.
518
00:28:37,340 --> 00:28:39,560
Also quite surprising to some folks.
519
00:28:40,080 --> 00:28:42,320
But anyway, there is some solution
here.
520
00:28:42,840 --> 00:28:48,900
However, problem like we need to
check every row in real time,
521
00:28:49,940 --> 00:28:51,300
it cannot go away.
522
00:28:51,820 --> 00:28:56,180
This is actually the number 1,
maybe the only 1 reason I think
523
00:28:56,180 --> 00:28:59,940
RLS, row level security is painful.
524
00:29:00,740 --> 00:29:02,720
Like how to solve it?
525
00:29:03,920 --> 00:29:09,240
Michael: I was reading the, there's
a really good gist put together
526
00:29:09,240 --> 00:29:13,660
by I think 1 of the team at Supabase and or at least they reference
527
00:29:13,660 --> 00:29:20,560
it in their docs. And they do mention
a kind of a trick where
528
00:29:20,560 --> 00:29:26,840
if as long as the function isn't
leaking any information, you
529
00:29:26,840 --> 00:29:28,760
could bypass RLS.
530
00:29:28,980 --> 00:29:32,320
So you can, I think it's called
security definer?
531
00:29:32,800 --> 00:29:36,760
You can set it up in a way that
the function can then bypass
532
00:29:36,900 --> 00:29:37,940
row level security.
533
00:29:39,720 --> 00:29:40,380
But yeah,
534
00:29:40,380 --> 00:29:43,240
Nikolay: I- But it feels like we're
turning off.
535
00:29:43,860 --> 00:29:44,260
Why?
536
00:29:44,260 --> 00:29:49,720
I can say, OK, let's run all massive
aggregate calls, like counts,
537
00:29:49,960 --> 00:29:51,240
sums, anything.
538
00:29:51,540 --> 00:29:55,820
Let's just run them using a User
which bypasses RLS.
539
00:29:56,920 --> 00:29:57,680
That's it.
540
00:29:58,660 --> 00:30:02,020
If you want to present some big
count somewhere, just do this.
541
00:30:02,020 --> 00:30:07,080
But if it's global it makes sense,
I would say okay here we need
542
00:30:07,080 --> 00:30:10,680
to count everything bypass RLS, we would do it anyway.
543
00:30:10,680 --> 00:30:16,120
But if it's inside single organization
it feels like breaking
544
00:30:16,120 --> 00:30:18,620
a hole in our wall we just built.
545
00:30:19,120 --> 00:30:23,440
Michael: I don't understand it
enough to understand why that
546
00:30:23,440 --> 00:30:25,840
might be okay and I think you would
have to be careful about
547
00:30:25,840 --> 00:30:29,220
not leaking information but because
of that first tip where we're
548
00:30:29,220 --> 00:30:33,040
still providing all the where clauses
we need to only be accessing
549
00:30:33,040 --> 00:30:35,640
that organization at the query
level.
550
00:30:36,100 --> 00:30:39,220
We've still got 1 level of security
there.
551
00:30:39,960 --> 00:30:44,300
So I can see why it's attractive,
but that's the only solution
552
00:30:44,300 --> 00:30:49,660
I saw to avoid doing it on every,
to avoid that check.
553
00:30:49,660 --> 00:30:51,000
Nikolay: It's logical problem.
554
00:30:51,220 --> 00:30:57,600
If we must definitely check, and
we do it after the player already
555
00:30:57,600 --> 00:31:01,380
did everything, and basically after
the last stage of execution,
556
00:31:01,400 --> 00:31:01,900
right?
557
00:31:03,480 --> 00:31:08,600
It's going to be super expensive
if you have a lot of rows before
558
00:31:08,600 --> 00:31:10,120
producing the final result.
559
00:31:10,920 --> 00:31:16,120
But I feel kind of like Postgres
could say, okay, we have it
560
00:31:16,520 --> 00:31:19,540
in the workloads, we already applied
this rule, let's skip it.
561
00:31:19,540 --> 00:31:22,500
This could be some optimization,
but it needs to be done inside
562
00:31:22,500 --> 00:31:24,300
Postgres somehow.
563
00:31:24,720 --> 00:31:26,520
I'm not sure if it was discussed.
564
00:31:26,520 --> 00:31:30,280
Michael: Well, like all planner
things, it would work, even if
565
00:31:30,280 --> 00:31:33,680
it was implemented for simple conditions,
it wouldn't work for
566
00:31:33,680 --> 00:31:34,620
some more complex.
567
00:31:35,220 --> 00:31:39,160
There would be a never-ending list
of quick, because these policies
568
00:31:39,160 --> 00:31:39,960
are so flexible.
569
00:31:39,960 --> 00:31:41,320
That's 1 of their strengths, right?
570
00:31:41,320 --> 00:31:43,980
You can set pretty much anything
as a policy.
571
00:31:43,980 --> 00:31:46,320
You can do it at the operation
level.
572
00:31:46,320 --> 00:31:49,900
You can do it at a role level,
you do so many different levels,
573
00:31:49,900 --> 00:31:52,940
and then you can pretty much, I
think you can use any SQL query
574
00:31:53,320 --> 00:31:55,760
to set up exactly the policy you
want.
575
00:31:55,760 --> 00:31:56,260
Nikolay: Yeah.
576
00:31:56,580 --> 00:31:59,380
Michael: Then you've got a whole
new planning issue, like the
577
00:31:59,380 --> 00:32:03,020
planners are already pretty complicated,
So I get why they haven't.
578
00:32:04,060 --> 00:32:04,720
Nikolay: I agree.
579
00:32:06,040 --> 00:32:09,560
For example, you know, in the check
constraints, you cannot refer
580
00:32:09,560 --> 00:32:10,460
to other tables.
581
00:32:14,380 --> 00:32:15,300
They are simple.
582
00:32:16,400 --> 00:32:21,380
But here in these policies, like
rules, we can do whatever we
583
00:32:21,380 --> 00:32:21,880
want.
584
00:32:21,980 --> 00:32:25,180
This means it's super, like what
I just proposed, probably it's
585
00:32:25,180 --> 00:32:26,820
impossible to implement, right?
586
00:32:27,060 --> 00:32:30,760
If it was just this table, no reference
to other table, Maybe
587
00:32:30,760 --> 00:32:34,640
current setting can be used and
the seat maybe there would be
588
00:32:34,640 --> 00:32:38,560
a way to Connect to the planner
and see okay.
589
00:32:38,560 --> 00:32:42,080
It's already applied this rule
that we can skip it Skip it in
590
00:32:42,080 --> 00:32:47,160
a safe manner 100% safe man reliable
manner, but if we can refer
591
00:32:47,160 --> 00:32:50,340
to any table write anything there
it's impossible
592
00:32:52,200 --> 00:32:53,720
Michael: or much more
593
00:32:53,720 --> 00:32:58,820
Nikolay: so many like predicates
like yeah so I agree with you
594
00:32:58,820 --> 00:32:59,320
here
595
00:32:59,760 --> 00:33:02,300
Michael: there's for people that
want that I will share I'll
596
00:33:02,300 --> 00:33:05,460
share a link to that gist there's
also a really good talk by
597
00:33:05,900 --> 00:33:09,820
Paul Copplestone, CEO of Supabase
from the last POSETTE conference
598
00:33:09,820 --> 00:33:13,580
I can share as well does a beginner's
guide to RLS but also covers
599
00:33:13,580 --> 00:33:17,100
some quite in-depth manages to
in about 20 minutes cover some
600
00:33:17,100 --> 00:33:19,920
quite in-depth performance tips
I think most of which we've covered
601
00:33:19,920 --> 00:33:22,800
now, but it's visual and you can
see him going through them,
602
00:33:22,800 --> 00:33:23,420
which is nice.
603
00:33:23,420 --> 00:33:23,800
Nikolay: Yeah.
604
00:33:23,800 --> 00:33:30,260
Well, I'm quite sure, like Supabase
and other systems which
605
00:33:30,300 --> 00:33:36,700
work with Postgres or Hasura or
something, these guys are at
606
00:33:36,700 --> 00:33:40,240
the frontier of RLS usage, right?
607
00:33:40,240 --> 00:33:45,740
And for sure a lot of experience
is in the discussions there,
608
00:33:46,980 --> 00:33:47,820
which is great.
609
00:33:48,800 --> 00:33:55,020
But I just see, still I feel like
we already had bad Aggregates
610
00:33:55,440 --> 00:33:59,620
you you made them worse Starting
starting using RLS.
611
00:33:59,620 --> 00:34:02,260
So yeah So By the
612
00:34:02,260 --> 00:34:03,873
Michael: way, I had a question
for you.
613
00:34:03,873 --> 00:34:07,940
Did you know how many times we've
had this topic requested for
614
00:34:07,940 --> 00:34:08,540
the podcast?
615
00:34:08,940 --> 00:34:10,020
Nikolay: I have no idea.
616
00:34:11,040 --> 00:34:11,780
Michael: 4 times.
617
00:34:12,180 --> 00:34:14,600
4 different people have requested
something.
618
00:34:15,780 --> 00:34:18,740
That's by far the most we've ever
had for a single topic.
619
00:34:19,540 --> 00:34:22,900
Nikolay: Okay, in this case we
should have a lot of feedback,
620
00:34:23,500 --> 00:34:24,140
I guess.
621
00:34:24,140 --> 00:34:24,640
Well,
622
00:34:25,080 --> 00:34:25,580
Michael: yeah.
623
00:34:25,940 --> 00:34:29,800
There are also a couple of people
asking about, like, when asked
624
00:34:29,800 --> 00:34:32,680
for more information, like what
exactly they wanted us to talk
625
00:34:32,680 --> 00:34:32,960
about.
626
00:34:32,960 --> 00:34:36,040
They asked about considerations
around performance, like how
627
00:34:36,040 --> 00:34:39,280
to then diagnose performance issues,
but I don't think there's
628
00:34:39,280 --> 00:34:40,760
anything unique about it, right?
629
00:34:40,760 --> 00:34:42,780
Like mostly it's still...
630
00:34:43,260 --> 00:34:44,520
Whoa, it's tricky,
631
00:34:44,640 --> 00:34:45,920
Nikolay: it's tricky, yeah.
632
00:34:46,020 --> 00:34:51,060
My, like, general rule is just
to compare with and without RLS
633
00:34:52,640 --> 00:34:55,940
For example, you can use user spaces.
634
00:34:55,960 --> 00:34:56,460
Yeah.
635
00:34:56,640 --> 00:35:00,560
Yeah, because it can be tricky
I of course you like filter and
636
00:35:00,560 --> 00:35:04,600
so on but I feel like in the plans
or maybe I'm missing something
637
00:35:04,600 --> 00:35:09,320
but I feel in the plans where like
we can start guessing how
638
00:35:09,320 --> 00:35:11,820
much time do we spend on an RLS
check.
639
00:35:12,640 --> 00:35:16,320
Michael: I well I think I think
personally if you're if you've
640
00:35:16,320 --> 00:35:19,940
already gone with RLS if you've
already decided that and you're
641
00:35:19,940 --> 00:35:24,640
well into your project, I think
the RLS checks don't matter that
642
00:35:24,640 --> 00:35:24,960
much.
643
00:35:24,960 --> 00:35:26,020
It's more indexing.
644
00:35:26,760 --> 00:35:31,280
I still see more people with indexing
issues than RLS performance
645
00:35:31,320 --> 00:35:31,820
issues.
646
00:35:32,540 --> 00:35:36,480
They look like RLS issues because
people might think that...
647
00:35:36,600 --> 00:35:37,280
I agree,
648
00:35:37,280 --> 00:35:37,800
Nikolay: I agree.
649
00:35:37,800 --> 00:35:42,760
But I'm talking about this massive
count, for example, like,
650
00:35:42,800 --> 00:35:46,720
you have a count on them and how
much of that time, like, how
651
00:35:46,720 --> 00:35:49,840
much, how big is the overhead from
our list?
652
00:35:49,840 --> 00:35:52,960
It's quite tricky without like
comparing 2 cases.
653
00:35:54,020 --> 00:35:58,680
I wish the EXPLAIN ANALYZE show
this.
654
00:35:58,680 --> 00:36:05,180
By the way, We just have BUFFERS
by default committed, right?
655
00:36:05,540 --> 00:36:07,840
We forgot to celebrate a little
bit.
656
00:36:07,840 --> 00:36:09,960
Maybe it should be a separate episode
about this.
657
00:36:09,960 --> 00:36:10,240
I don't
658
00:36:10,240 --> 00:36:10,380
Michael: know.
659
00:36:10,380 --> 00:36:14,960
I think I want to wait until Postgres
18 to celebrate that, or
660
00:36:14,960 --> 00:36:17,640
at least far into the future to
release candidates.
661
00:36:17,640 --> 00:36:19,040
Nikolay: I cannot believe this.
662
00:36:19,540 --> 00:36:20,720
It's super great, right?
663
00:36:21,400 --> 00:36:23,720
Michael: Yeah, a couple of things
people to thank on that front.
664
00:36:23,720 --> 00:36:28,680
I think David Rowley did a really
good job and also Guillaume
665
00:36:28,680 --> 00:36:32,060
Lellouche did a lot of the heavy
lifting as well.
666
00:36:32,180 --> 00:36:34,800
So those 2 in particular, there
was a really good conversation
667
00:36:34,840 --> 00:36:37,380
on the mailing list that I think
you kicked off actually.
668
00:36:38,400 --> 00:36:41,240
Nikolay: I didn't expect at this
time it will go through.
669
00:36:42,720 --> 00:36:45,580
I was discussing things near this
topic, right?
670
00:36:46,060 --> 00:36:50,540
But I'm happy to see it and I guess
I will need to find another
671
00:36:50,540 --> 00:36:52,760
topic to be upset with.
672
00:36:53,400 --> 00:36:57,940
Because it was more than 2 years
I was talking about how I'm
673
00:36:57,940 --> 00:37:00,040
upset that BUFFERS are not default.
674
00:37:00,720 --> 00:37:02,340
And it's going to be over.
675
00:37:02,980 --> 00:37:08,860
I feel happy and sad at the same
time Another thing was UUID
676
00:37:08,860 --> 00:37:15,140
version 7 finally Right, and you
know what like my perception
677
00:37:15,360 --> 00:37:20,560
was we were waiting until full
finalization of RFC, right?
678
00:37:21,180 --> 00:37:22,480
Michael: Oh, I forgot to say too.
679
00:37:22,660 --> 00:37:23,980
Nikolay: Yeah, because everyone...
680
00:37:24,140 --> 00:37:25,147
Michael: Is it not being finalized?
681
00:37:25,147 --> 00:37:28,640
Nikolay: It was developed before
Postgres 17 released and then
682
00:37:29,040 --> 00:37:33,080
the decision was made not to take
it into 17 because RFC is not
683
00:37:33,080 --> 00:37:33,980
fully finalized.
684
00:37:34,200 --> 00:37:38,300
At the same time, everyone already
started releasing UUID support
685
00:37:38,300 --> 00:37:43,380
like Node.js, Go, like Google decided
to release it, everyone
686
00:37:43,380 --> 00:37:45,460
already, but Postgres decided to stay
conservative.
687
00:37:45,700 --> 00:37:51,140
The thing is that, unless I'm fully
mistaken, I see RFC is not
688
00:37:51,140 --> 00:37:52,720
fully finalized yet.
689
00:37:53,400 --> 00:37:53,560
Michael: Amazing.
690
00:37:53,560 --> 00:37:54,060
Still.
691
00:37:54,840 --> 00:37:57,340
So maybe it will be before 18's
released?
692
00:37:57,340 --> 00:38:01,160
Nikolay: Andrey told me not to
shout about this.
693
00:38:02,220 --> 00:38:03,000
Michael: Probably sensible.
694
00:38:03,280 --> 00:38:07,940
Andrey and I have similar philosophies
then, wait until it's
695
00:38:07,940 --> 00:38:09,580
actually released before celebrating.
696
00:38:09,580 --> 00:38:12,520
Nikolay: Yeah I bet we can talk
about these things here because
697
00:38:12,520 --> 00:38:14,820
hackers don't listen to us right
so.
698
00:38:14,840 --> 00:38:16,360
Michael: I think a couple days.
699
00:38:16,940 --> 00:38:20,060
Nikolay: They won't go and say
let's revert it I hope.
700
00:38:20,240 --> 00:38:25,680
Anyway congrats to Andrey because
this is who coded it, This
701
00:38:25,680 --> 00:38:29,600
is him who coded this during our Postgres TV live coding, hacking
702
00:38:29,600 --> 00:38:32,000
sessions with Kirk and Andrey.
703
00:38:32,140 --> 00:38:36,880
So yeah, this week was, to commit, surprised me.
704
00:38:37,360 --> 00:38:41,600
Both things I'm like very passionate about, like buffers by default
705
00:38:41,600 --> 00:38:47,080
in Explain, Analyze, and UID version 7, I think, again, like
706
00:38:47,080 --> 00:38:50,640
people who listen to us, don't wait until the release of those
707
00:38:51,140 --> 00:38:56,100
functions, UUIDv7, start using it right now because it's just,
708
00:38:56,100 --> 00:38:57,680
basically, it's synthetic sugar.
709
00:38:57,800 --> 00:39:02,960
Not fully, but you can start using UUID data type and insert
710
00:39:02,960 --> 00:39:07,660
UUID version 7 generated on application side, or using some SQL
711
00:39:07,660 --> 00:39:09,220
function, PGSQL function.
712
00:39:09,220 --> 00:39:10,780
I have examples in my how-tos.
713
00:39:11,640 --> 00:39:15,940
And when this feature becomes native, switch to native.
714
00:39:16,400 --> 00:39:21,820
But it's hard to overestimate the importance of this support
715
00:39:21,820 --> 00:39:25,440
because you know I can convince a couple of guys to start using
716
00:39:25,440 --> 00:39:26,180
right now.
717
00:39:26,180 --> 00:39:31,440
Some guys can guess but 90% will follow default path right?
718
00:39:31,920 --> 00:39:32,920
Michael: Same with buffers.
719
00:39:34,020 --> 00:39:34,520
Nikolay: Exactly.
720
00:39:35,140 --> 00:39:37,280
Michael: People can start using it now, there's no reason they
721
00:39:37,280 --> 00:39:40,440
can't use it now, it's just more will once it's there.
722
00:39:40,440 --> 00:39:43,780
Nikolay: We will finally analyze plans with buffers always and
723
00:39:43,780 --> 00:39:50,160
let's like to wrap it up, when you see overhead from RLS, it's
724
00:39:50,160 --> 00:39:52,160
not about buffers, usually.
725
00:39:52,540 --> 00:39:55,060
Unless it's a lack of index.
726
00:39:55,640 --> 00:39:59,320
But if this is like current setting, we talked about current
727
00:39:59,320 --> 00:40:01,600
setting on each row, it's called.
728
00:40:02,620 --> 00:40:06,540
Buffers are like tiny, but timing is awful.
729
00:40:07,880 --> 00:40:11,300
And yeah, this is 1 of the rare cases where buffers...
730
00:40:11,760 --> 00:40:13,260
Well, buffers don't lie, right?
731
00:40:13,260 --> 00:40:14,160
They don't lie.
732
00:40:14,220 --> 00:40:15,720
They show there is no I/O
733
00:40:15,720 --> 00:40:16,220
Here.
734
00:40:16,400 --> 00:40:17,980
And it's already useful information.
735
00:40:18,560 --> 00:40:19,060
But...
736
00:40:19,340 --> 00:40:20,420
Michael: But you need both.
737
00:40:21,020 --> 00:40:22,100
Nikolay: You need both, right.
738
00:40:22,100 --> 00:40:26,840
And you know, sometimes I say, most of the time we optimize targeting
739
00:40:26,840 --> 00:40:27,340
buffers.
740
00:40:27,400 --> 00:40:32,140
In this case, we don't because it's just not about I/O
741
00:40:32,140 --> 00:40:32,780
at all.
742
00:40:32,960 --> 00:40:34,340
But seeing that I/O
743
00:40:34,340 --> 00:40:36,720
is low, it already gives us idea.
744
00:40:37,420 --> 00:40:39,040
Maybe it's RLS, right.
745
00:40:40,160 --> 00:40:41,020
Michael: Nice 1, Nikolay.
746
00:40:41,680 --> 00:40:44,320
Well, thanks again and catch you soon.
747
00:40:44,760 --> 00:40:46,640
Nikolay: See you later, bye bye, thank you.
00:00:00,060 --> 00:00:03,680
Nikolay: Hello, hello, this is
PostgresFM, podcast about PostgreSQL.
2
00:00:04,920 --> 00:00:06,540
Do I pronounce it right, Michael?
3
00:00:06,660 --> 00:00:07,580
Michael: I think so.
4
00:00:07,840 --> 00:00:08,140
Nikolay: Yeah.
5
00:00:08,140 --> 00:00:09,100
And hi, Michael.
6
00:00:09,340 --> 00:00:10,420
Michael from pgMustard.
7
00:00:11,600 --> 00:00:12,640
Michael: Hello, Nikolay.
8
00:00:12,640 --> 00:00:15,340
Nikolay: Yeah, and I'm Nikolay,
Postgres.AI.
9
00:00:15,340 --> 00:00:16,520
And let's...
10
00:00:16,860 --> 00:00:18,920
We don't have guests today, unfortunately.
11
00:00:19,540 --> 00:00:22,720
We have good guests coming soon,
but not this time.
12
00:00:24,240 --> 00:00:28,440
My idea was, you know how much
I don't like to deal with security.
13
00:00:28,660 --> 00:00:30,560
I just need to do it.
14
00:00:31,260 --> 00:00:34,500
Let's talk about policies, create
policy.
15
00:00:35,500 --> 00:00:37,520
Why is it create policy, by the
way?
16
00:00:37,540 --> 00:00:41,140
It's not create RLS policy, it's
just create policy.
17
00:00:42,260 --> 00:00:45,280
Policy is a very general word,
right?
18
00:00:45,280 --> 00:00:49,700
It can be not only row level security,
maybe some other policies.
19
00:00:50,660 --> 00:00:53,540
Do you think the decision was made
to...
20
00:00:54,140 --> 00:00:55,540
I think this is not standard.
21
00:00:55,840 --> 00:00:59,920
I'm not sure because I just checked
with some AI and it says
22
00:01:00,060 --> 00:01:02,820
SQL standard doesn't have RLS.
23
00:01:03,620 --> 00:01:06,160
Michael: I looked up where did
the name come from because it
24
00:01:06,160 --> 00:01:09,060
wasn't the title of the page in
the Postgres documentation.
25
00:01:10,440 --> 00:01:13,100
And the time it's used is in the
alter table statement.
26
00:01:13,100 --> 00:01:16,320
So this is a table level setting
that you first enable.
27
00:01:16,560 --> 00:01:20,100
And only once you've enabled it
on the table, then you set policies.
28
00:01:20,660 --> 00:01:25,520
So it's alter table, and then enable
row level security, and
29
00:01:25,520 --> 00:01:29,700
then once that's enabled, you need
to create at least 1 policy
30
00:01:29,700 --> 00:01:32,860
so that people, or non-superusers,
can read anything.
31
00:01:33,260 --> 00:01:37,120
Nikolay: Right, but still, it confused
me from the very beginning.
32
00:01:37,120 --> 00:01:41,180
I think it was implemented originally
very long ago, right, before
33
00:01:41,320 --> 00:01:44,020
Postgres 10 or after, I don't remember.
34
00:01:44,020 --> 00:01:45,560
Michael: I didn't actually check
this time.
35
00:01:45,600 --> 00:01:48,540
Nikolay: Yeah, but I think it's
quite old feature relatively.
36
00:01:50,140 --> 00:01:55,760
It definitely wasn't in Postgres
9.0, but possibly it's already
37
00:01:55,760 --> 00:01:56,620
present in...
38
00:01:57,040 --> 00:01:58,280
Michael: I found it in 9.5.
39
00:01:58,780 --> 00:02:00,040
Nikolay: 9.5, yeah.
40
00:02:00,240 --> 00:02:02,960
It means 2015 or something, right?
41
00:02:03,900 --> 00:02:09,060
So let's talk about the problem
it's solving or tries to solve.
42
00:02:09,400 --> 00:02:15,400
Problem is in the era of SaaS,
software as a service, We have
43
00:02:15,400 --> 00:02:21,340
a lot of cases when 1 system running
in cloud operates with many,
44
00:02:21,340 --> 00:02:30,860
many different users which ideally
should not put at risk each
45
00:02:30,860 --> 00:02:31,860
other or something.
46
00:02:32,120 --> 00:02:33,300
There should be some segregation.
47
00:02:33,540 --> 00:02:37,600
For example, if we have, say, like
Twitter style, right?
48
00:02:37,600 --> 00:02:39,520
We have users, we have...
49
00:02:39,900 --> 00:02:41,200
No, Twitter is not good.
50
00:02:41,200 --> 00:02:44,020
Let's think about something more
business-oriented.
51
00:02:44,460 --> 00:02:45,300
It will be more...
52
00:02:45,300 --> 00:02:48,840
Michael: Or e-commerce, being able
to see somebody else's orders
53
00:02:48,840 --> 00:02:51,700
or being able to see their address
or something like that.
54
00:02:51,880 --> 00:02:55,960
Nikolay: Let's find some B2B example
because this is where it
55
00:02:55,960 --> 00:02:59,960
feels much more sound, so to speak.
56
00:02:59,960 --> 00:03:03,980
So, for example, let's take Slack
and we try to implement Slack,
57
00:03:04,000 --> 00:03:04,500
right?
58
00:03:05,280 --> 00:03:10,380
So we have workspaces, many of
them, and channels inside and
59
00:03:10,380 --> 00:03:14,060
people communicate, but each workspace
belongs to some customer,
60
00:03:14,060 --> 00:03:16,340
some organization which uses our
service.
61
00:03:16,480 --> 00:03:17,700
And it's SaaS, right?
62
00:03:17,800 --> 00:03:18,660
It's in cloud.
63
00:03:19,180 --> 00:03:23,480
And is it a good idea to keep all
messages, for example, in a
64
00:03:23,480 --> 00:03:27,240
single, maybe partition, but we
forget about performance for
65
00:03:27,240 --> 00:03:32,840
a while, in a single table called
like messages for all customers?
66
00:03:33,680 --> 00:03:35,900
Maybe it's a good idea, maybe not,
right?
67
00:03:35,900 --> 00:03:41,620
But from security point of view,
it's terrible idea because if
68
00:03:41,880 --> 00:03:48,120
selecting our messages, we have
some bug or some kind of hacker
69
00:03:48,120 --> 00:03:52,860
attack, we can select other organization
messages, right?
70
00:03:53,560 --> 00:03:54,520
And that's bad.
71
00:03:55,080 --> 00:04:00,660
So, or maybe just developer forgot
to put some condition, again,
72
00:04:00,660 --> 00:04:03,140
a bug or something like unintentional.
73
00:04:04,280 --> 00:04:09,100
And suddenly 1 organization deals
with messages from other organizations.
74
00:04:09,720 --> 00:04:11,880
It sounds super scary, right?
75
00:04:13,660 --> 00:04:17,140
For platform development, I mean
for the SaaS service developers,
76
00:04:17,360 --> 00:04:18,220
it's bad.
77
00:04:18,960 --> 00:04:23,940
So my point is, some SaaS systems
still have this situation.
78
00:04:24,620 --> 00:04:27,320
Old ones definitely have this situation
unresolved.
79
00:04:28,680 --> 00:04:28,780
And
80
00:04:28,780 --> 00:04:29,280
Michael: most.
81
00:04:30,040 --> 00:04:30,360
I think
82
00:04:30,360 --> 00:04:30,600
Nikolay: it
83
00:04:30,600 --> 00:04:32,180
Michael: might be most, yeah.
84
00:04:32,780 --> 00:04:35,900
Nikolay: Yeah, ultimate, so it's
called multi-tenant system,
85
00:04:35,900 --> 00:04:36,400
right?
86
00:04:37,280 --> 00:04:42,040
Ultimate way is like you create
a database or maybe it's like
87
00:04:42,100 --> 00:04:46,820
whole cluster for each, at least
big customer and that's it,
88
00:04:46,820 --> 00:04:47,320
right?
89
00:04:47,400 --> 00:04:51,160
And full segregation, full separation
of data, and that's great,
90
00:04:51,160 --> 00:04:52,700
but it's super expensive.
91
00:04:53,300 --> 00:04:58,080
Even if you put it in the same
database, in the same schema,
92
00:04:58,080 --> 00:05:01,200
but in different tables, it's also
quite expensive.
93
00:05:01,560 --> 00:05:04,900
Although we know Postgres can live
with millions of tables.
94
00:05:05,540 --> 00:05:10,160
I can send you a new Presentation
we just recently discussed
95
00:05:10,160 --> 00:05:12,720
it wasn't probably Presented in
Brazil.
96
00:05:12,720 --> 00:05:15,280
I don't remember again like hundred
million tables.
97
00:05:15,280 --> 00:05:15,940
Is it possible?
98
00:05:15,940 --> 00:05:20,040
Well, it's possible, but it's difficult.
99
00:05:20,660 --> 00:05:24,360
So the idea of RLS comes from this
problem.
100
00:05:24,480 --> 00:05:29,360
We want to have guaranteed protection
that 1 customer sees only
101
00:05:29,640 --> 00:05:32,680
their data, not other customers' data.
102
00:05:32,680 --> 00:05:37,860
And it can be achieved by defining special rule that additional
103
00:05:39,020 --> 00:05:43,140
condition will be always present in selects right or updates
104
00:05:43,140 --> 00:05:44,560
deletes inserts
105
00:05:44,600 --> 00:05:47,580
Michael: yeah and I think I think would you say it's fair that
106
00:05:47,680 --> 00:05:51,100
most, when I said most don't have this, I mean most don't have
107
00:05:51,100 --> 00:05:52,360
it at the database level.
108
00:05:52,360 --> 00:05:55,580
I think most people put a lot of effort into making sure this
109
00:05:55,580 --> 00:05:59,820
couldn't happen at the application level, but most don't also
110
00:05:59,860 --> 00:06:03,420
add an additional level, like layer of defense at the database
111
00:06:03,420 --> 00:06:03,640
level.
112
00:06:03,640 --> 00:06:06,780
And this is a database level, so any application sitting on top
113
00:06:06,780 --> 00:06:10,140
of it, or any client sitting on top of it, gets that by default.
114
00:06:10,420 --> 00:06:13,220
Nikolay: Yeah, that's why I always say we cannot trust the application
115
00:06:13,480 --> 00:06:17,120
layer, because what if next year your organization decides to
116
00:06:17,120 --> 00:06:20,140
try a new framework or something and you have 2 applications
117
00:06:20,320 --> 00:06:23,040
and they behave differently or you need to deal with implementing
118
00:06:23,040 --> 00:06:25,880
the same rules in 2 systems and basically copy-pasting.
119
00:06:26,880 --> 00:06:30,040
Sometimes in different languages it's super hard to maintain.
120
00:06:30,880 --> 00:06:35,440
What if you have some specific interfaces connected to database
121
00:06:35,440 --> 00:06:39,880
and people just work with this data directly, right?
122
00:06:40,840 --> 00:06:43,460
They bypass your application logic completely.
123
00:06:45,480 --> 00:06:49,240
This is good to have inside the database, closer to data, and
124
00:06:49,340 --> 00:06:51,380
applied in the same manner to all.
125
00:06:51,580 --> 00:06:55,140
I wanted to say this problem can be solved using views.
126
00:06:57,260 --> 00:07:01,720
So you can, for example, have a view which will deal only with
127
00:07:01,720 --> 00:07:07,660
data dynamically for a particular customer only, not seeing anything
128
00:07:07,660 --> 00:07:08,160
else.
129
00:07:08,680 --> 00:07:13,880
You just put something to the rule definition, which will involve
130
00:07:14,140 --> 00:07:16,120
some current setting again.
131
00:07:16,880 --> 00:07:20,000
And in the current setting you have your customer ID, for example,
132
00:07:20,000 --> 00:07:25,700
and you say, okay, this view is selecting rows from messages
133
00:07:25,800 --> 00:07:30,780
table, where, and we have the check that customer, like project
134
00:07:30,780 --> 00:07:34,020
ID, organization ID, doesn't matter, it belongs to this customer
135
00:07:34,020 --> 00:07:34,960
ID, that's it.
136
00:07:34,960 --> 00:07:35,420
Always.
137
00:07:35,420 --> 00:07:36,800
It can be joined maybe.
138
00:07:37,280 --> 00:07:41,780
And in this case, this view can be even writable, so inserts,
139
00:07:41,780 --> 00:07:43,220
deletes, updates could work.
140
00:07:43,900 --> 00:07:46,680
And this check is automatically verified.
141
00:07:47,060 --> 00:07:49,280
Although maybe it's not verified at insert time.
142
00:07:49,280 --> 00:07:50,280
I don't remember exactly.
143
00:07:50,280 --> 00:07:52,100
I think there is some caveat here.
144
00:07:54,520 --> 00:07:58,140
But if we think about only selects at least, it's definitely
145
00:07:58,140 --> 00:07:58,640
working.
146
00:08:00,060 --> 00:08:03,680
If you make your application work only with this view, not with
147
00:08:03,680 --> 00:08:09,060
the original underlying table, in this case you can be 100% sure
148
00:08:09,060 --> 00:08:13,960
that they will see only data they can see, not anything else.
149
00:08:15,740 --> 00:08:19,240
This additional filter will be always—planner will be always
150
00:08:19,240 --> 00:08:20,060
using it.
151
00:08:20,580 --> 00:08:23,800
But this is not RLS, it's an alternative
approach.
152
00:08:23,860 --> 00:08:25,380
And I think inserts will be a problem.
153
00:08:25,380 --> 00:08:29,540
I don't remember 100%, but I remember
I was, I got bitten by
154
00:08:29,540 --> 00:08:34,200
this problem a few times in my
experience, and we needed to implement
155
00:08:34,200 --> 00:08:37,440
triggers to double-check that inserts
are protected and the same
156
00:08:37,440 --> 00:08:39,780
rule is applied the third time.
157
00:08:40,020 --> 00:08:42,940
So maybe this is like downside
of this approach.
158
00:08:43,940 --> 00:08:51,160
But create policy statement is
more like natural way to protect
159
00:08:51,180 --> 00:08:52,740
data for these purposes, right?
160
00:08:52,740 --> 00:08:59,580
So we define a policy and we alter
a table saying that row level
161
00:08:59,620 --> 00:09:01,420
security is enabled for this table.
162
00:09:01,420 --> 00:09:02,700
By default, it's not, right?
163
00:09:02,800 --> 00:09:04,580
Michael: Well, yeah, in Postgres,
yeah.
164
00:09:04,840 --> 00:09:08,040
Nikolay: Yeah, and then this policy
is supposed to protect us
165
00:09:08,080 --> 00:09:12,940
in terms of multi-tenant situations,
so customers deal only with
166
00:09:12,940 --> 00:09:15,640
the data they can deal with, they
don't see each other.
167
00:09:15,940 --> 00:09:19,060
Do you think it's a good protection
for multi-tenant situation
168
00:09:19,940 --> 00:09:21,900
when we keep everything in 1 table?
169
00:09:22,200 --> 00:09:24,400
Michael: I have mixed feelings
about role of security.
170
00:09:24,520 --> 00:09:28,340
I think this is a security question
in general.
171
00:09:28,820 --> 00:09:31,820
How much are the downsides worth
it?
172
00:09:31,820 --> 00:09:34,840
How much is the extra complexity
worth it for the additional
173
00:09:34,840 --> 00:09:41,100
security and yeah I think in environments
where security is of
174
00:09:41,100 --> 00:09:45,100
paramount importance it makes sense
to add security at every
175
00:09:45,100 --> 00:09:47,100
level including this
176
00:09:47,520 --> 00:09:50,200
Nikolay: 1 this 1 I mean you mean
database level
177
00:09:50,360 --> 00:09:53,600
Michael: yeah I don't see Postgres
very level security in use
178
00:09:53,600 --> 00:09:57,800
that much so most people seem to
be making the trade-off of not
179
00:09:57,800 --> 00:10:02,520
using it in favor well not in favor
of I suspect most people
180
00:10:02,520 --> 00:10:06,100
using row level Security also have
other measures in place.
181
00:10:06,660 --> 00:10:10,020
But I've seen a growing number
of performance related questions
182
00:10:10,020 --> 00:10:12,180
around Rail-Level Security in various
communities.
183
00:10:12,720 --> 00:10:18,620
And I think it's due to the popularity
of PostgREST and the
184
00:10:18,680 --> 00:10:20,840
automatic creating.
185
00:10:20,860 --> 00:10:26,000
Also, my theory is because people
are creating these RESTful
186
00:10:26,000 --> 00:10:31,780
APIs directly interfacing with
the database, it becomes super
187
00:10:31,780 --> 00:10:34,900
important to have security at the
database level because people
188
00:10:34,900 --> 00:10:36,940
can change the parameters of the
URL.
189
00:10:37,200 --> 00:10:41,080
And otherwise, they could just
view other people's data immediately.
190
00:10:41,580 --> 00:10:44,620
So I think it makes sense that
it's growing in popularity.
191
00:10:44,620 --> 00:10:47,320
But I don't think it's been growing
in popularity as an additional
192
00:10:47,360 --> 00:10:47,640
layer.
193
00:10:47,640 --> 00:10:50,640
I think it's been growing in popularity
as the only layer.
194
00:10:50,660 --> 00:10:51,660
But I could be wrong.
195
00:10:51,660 --> 00:10:54,900
Nikolay: Yeah, that's interesting,
because exactly this alternative
196
00:10:54,920 --> 00:10:58,220
approach, which I explained using
views, it's coming.
197
00:10:59,060 --> 00:11:04,080
Actually, my bachelor thesis was
about updatable views, and master
198
00:11:04,080 --> 00:11:06,740
thesis was about updatable XML
views.
199
00:11:06,900 --> 00:11:09,220
So it was like 20 years plus ago.
200
00:11:09,520 --> 00:11:15,220
But Postgres particularly provokes
you to use views over tables
201
00:11:15,220 --> 00:11:15,880
and views.
202
00:11:15,880 --> 00:11:21,200
You just create a view in, say,
by default, schema v1, and this
203
00:11:21,200 --> 00:11:24,440
is your v1 version 1 API.
204
00:11:25,160 --> 00:11:31,520
By creating views and controlling
who can see what, you can already
205
00:11:31,520 --> 00:11:33,300
limit access.
206
00:11:34,460 --> 00:11:38,000
You can hide some columns, just
not taking them to views, and
207
00:11:38,000 --> 00:11:38,700
so on.
208
00:11:39,340 --> 00:11:43,380
And that's great, but maybe you
are right, because I did see
209
00:11:43,380 --> 00:11:47,940
some popularity of low-level security
growing from that side.
210
00:11:48,160 --> 00:11:52,260
Because people need more and more
and more logic on database
211
00:11:52,260 --> 00:11:56,180
side, which is related to data,
because there is no middleware.
212
00:11:56,460 --> 00:12:00,180
It's only this high-skill application
called Postgres.
213
00:12:00,940 --> 00:12:04,400
And all the data-related logic
is supposed to be in database,
214
00:12:04,600 --> 00:12:06,660
including everything related to
permissions.
215
00:12:07,720 --> 00:12:11,880
And all UI logic is on FAT client,
right?
216
00:12:11,880 --> 00:12:13,500
It's like React or something.
217
00:12:14,240 --> 00:12:16,820
And, Yeah, I see your point.
218
00:12:16,820 --> 00:12:17,320
Exactly.
219
00:12:17,320 --> 00:12:23,160
If you have middleware, Ruby, Python,
Java, anything, then people
220
00:12:23,160 --> 00:12:26,120
tend to implement all the security
checks right there, right?
221
00:12:26,120 --> 00:12:29,160
And maintain them in a unified
way and so on.
222
00:12:29,160 --> 00:12:29,940
Yeah, I agree.
223
00:12:30,100 --> 00:12:32,980
There's no application, middleware
application here.
224
00:12:32,980 --> 00:12:35,860
So it goes to database or where
else, right?
225
00:12:35,860 --> 00:12:37,480
Because it cannot go to UI.
226
00:12:37,540 --> 00:12:40,320
But interesting, again, views are
there as well, but it's not
227
00:12:40,320 --> 00:12:40,660
enough.
228
00:12:40,660 --> 00:12:42,100
It doesn't feel enough.
229
00:12:42,440 --> 00:12:46,420
And sometimes we need to deal with
data from multiple clients.
230
00:12:46,840 --> 00:12:48,080
Sometimes, it depends, right?
231
00:12:48,080 --> 00:12:50,820
Because, I mean, admin mode or
something, right?
232
00:12:51,340 --> 00:12:56,000
Yeah, in this case, ROLL security
provides this bypass RLS flag
233
00:12:56,000 --> 00:12:59,540
for when you create a role or user,
you can specify this flag,
234
00:12:59,540 --> 00:13:03,420
it's kind of super user, not super
user, but it bypasses these
235
00:13:03,420 --> 00:13:04,780
security checks, right?
236
00:13:05,140 --> 00:13:05,980
Yeah, I agree.
237
00:13:05,980 --> 00:13:10,460
And then, but my point stands as
well, like old SaaS systems,
238
00:13:10,520 --> 00:13:16,400
they tend to not using RLS, but
there are many other fresh, like
239
00:13:16,860 --> 00:13:22,200
last few years, a lot of SaaS systems
are created, have been
240
00:13:22,200 --> 00:13:27,800
created, and still created, and
also with AI, it's also very
241
00:13:27,800 --> 00:13:31,800
much standard situation sometimes
think about charge BT as well
242
00:13:31,960 --> 00:13:35,100
It's also like kind of many messages
from these chats.
243
00:13:35,280 --> 00:13:38,320
It can be also single table and
it requires some security as
244
00:13:38,320 --> 00:13:38,980
well, right?
245
00:13:39,240 --> 00:13:43,260
And my point is that new SaaS systems,
they tend to have it even
246
00:13:43,260 --> 00:13:48,160
without Postgres or Hasura or something
like that.
247
00:13:48,900 --> 00:13:55,340
Even if they use regular Django
or Java or anything, they sometimes,
248
00:13:55,380 --> 00:13:59,300
I just observed it, they sometimes
implement RLS because they
249
00:13:59,300 --> 00:14:03,620
think, okay, we need better protection
for our SaaS system.
250
00:14:05,080 --> 00:14:05,740
Multi-tenant system.
251
00:14:05,740 --> 00:14:07,480
Michael: Cool, I didn't realize that, that's great.
252
00:14:07,480 --> 00:14:10,240
Nikolay: Yeah, I just see it, and then they grow and start hitting
253
00:14:10,240 --> 00:14:11,260
performance issues.
254
00:14:13,320 --> 00:14:17,080
And this is natural, And it looks like the first, let's talk
255
00:14:17,080 --> 00:14:18,740
about performance, if you don't mind.
256
00:14:19,120 --> 00:14:21,680
Michael: No, I think the most interesting part of this
257
00:14:21,680 --> 00:14:22,360
Nikolay: is performance.
258
00:14:23,260 --> 00:14:28,180
And the first thing they bump into sometimes, not everyone, is
259
00:14:28,180 --> 00:14:33,580
that having some condition present in the RLS definition, this
260
00:14:33,800 --> 00:14:37,220
filtering, doesn't mean that the planner will see it.
261
00:14:37,360 --> 00:14:39,980
You can have an index on a column.
262
00:14:40,200 --> 00:14:41,760
For example, it's a simple condition.
263
00:14:42,040 --> 00:14:43,520
Some column equals some constant.
264
00:14:43,520 --> 00:14:47,200
Forget about current setting or some stable functions for a while.
265
00:14:47,420 --> 00:14:48,180
Some constant.
266
00:14:48,700 --> 00:14:52,920
And we have an index on this column, but we don't have this condition
267
00:14:53,700 --> 00:14:55,420
used in the where clause.
268
00:14:56,520 --> 00:14:59,600
This will lead to sequential scan, right?
269
00:14:59,600 --> 00:15:03,460
Because planner doesn't see what row level security is going
270
00:15:03,460 --> 00:15:06,400
to, which filter is going to apply, right?
271
00:15:07,100 --> 00:15:08,060
And this is surprise.
272
00:15:09,060 --> 00:15:12,260
Michael: Yeah, sequential scan, but like with a filter so each
273
00:15:12,260 --> 00:15:14,440
1 will be checked against the policy
274
00:15:16,260 --> 00:15:17,340
Nikolay: Just use it
275
00:15:18,380 --> 00:15:20,820
Michael: You might even yes, even if you have an index on that.
276
00:15:20,820 --> 00:15:24,100
So yeah, that's super unintuitive, I think, for people.
277
00:15:24,520 --> 00:15:27,300
And it tripped me up when I was reading about this.
278
00:15:27,620 --> 00:15:33,900
I thought, I wondered if it could use an index on a simple policy,
279
00:15:34,040 --> 00:15:37,620
on a column, like a user ID or something like that.
280
00:15:37,900 --> 00:15:41,680
And I even saw guides, in fact, there's a really good guide on
281
00:15:41,680 --> 00:15:45,900
row level security by the team at Supabase who heavily encourage
282
00:15:46,360 --> 00:15:51,340
the use of row level security as part of their offering because
283
00:15:51,340 --> 00:15:52,320
they're using Postgres.
284
00:15:53,080 --> 00:15:56,760
But yeah, they say you can think of policies as adding a where
285
00:15:56,760 --> 00:15:58,020
clause to every query.
286
00:15:58,520 --> 00:16:01,500
But that tripped me up When it came to performance because it's
287
00:16:01,500 --> 00:16:03,900
not like a where clause from a performance perspective.
288
00:16:03,900 --> 00:16:07,460
It's like a where clause from like a user experience perspective
289
00:16:07,540 --> 00:16:11,680
like from a from what you see at the end of the Data coming back
290
00:16:11,680 --> 00:16:14,820
might might look the same as if you'd feel today using a where
291
00:16:14,820 --> 00:16:18,040
clause But performance like the planner doesn't have access to
292
00:16:18,040 --> 00:16:21,660
that to choose to do a different type of scan at the beginning.
293
00:16:21,820 --> 00:16:26,400
So yeah, super important distinction and 1 of their tips on the
294
00:16:26,400 --> 00:16:29,600
performance side is therefore to always include all the filters
295
00:16:29,600 --> 00:16:31,900
you want anyway in the queries.
296
00:16:32,320 --> 00:16:34,800
Nikolay: Yeah Yeah, that's interesting.
297
00:16:35,240 --> 00:16:38,360
But it's easy to solve, I think.
298
00:16:38,420 --> 00:16:41,680
Just add it there, into the where class, and that's it.
299
00:16:42,340 --> 00:16:46,500
Let's talk about, step back maybe a little bit about not performance,
300
00:16:46,840 --> 00:16:50,240
because I will forget about this, but I wanted to share some
301
00:16:50,500 --> 00:16:51,820
feature stuff.
302
00:16:51,820 --> 00:16:56,840
First of all, I saw the case that
if we have foreign keys and
303
00:16:56,840 --> 00:17:01,160
so on, referential integrity checks
are not covered, right?
304
00:17:01,560 --> 00:17:06,220
This is like, like, the integrity
is more important than role
305
00:17:06,220 --> 00:17:07,540
level security, right?
306
00:17:07,740 --> 00:17:10,640
Did you see any interesting cases
related to this?
307
00:17:11,320 --> 00:17:14,660
Michael: Well, I only read about,
I thought it was a really fascinating
308
00:17:15,560 --> 00:17:20,140
concept that by enforcing referential
integrity you could be
309
00:17:20,140 --> 00:17:22,460
leaking security information like
if you...
310
00:17:22,460 --> 00:17:24,400
Nikolay: Or inserting something
which is not...
311
00:17:24,400 --> 00:17:27,100
Michael: Yeah exactly if you're
1 user trying to insert something
312
00:17:27,380 --> 00:17:33,120
and you find out that it that it
fails to be inserted then you
313
00:17:33,120 --> 00:17:35,760
know that thing exists but from
some other user.
314
00:17:35,760 --> 00:17:38,760
Nikolay: Insert is a bad example,
because foreign key doesn't
315
00:17:38,760 --> 00:17:39,340
help with insert.
316
00:17:39,340 --> 00:17:41,680
It helps with, for example, deletes,
right?
317
00:17:41,680 --> 00:17:42,840
Like, SK deletes.
318
00:17:43,480 --> 00:17:47,140
So you, for example, can delete
what you cannot see or something
319
00:17:47,140 --> 00:17:47,680
like that.
320
00:17:47,680 --> 00:17:48,900
Michael: Yeah, Yeah, sorry, good
point.
321
00:17:48,900 --> 00:17:51,800
Maybe it's not relevant then, but
I did read in the documentation
322
00:17:52,660 --> 00:17:58,780
that you need to be careful with
leaking information by checking...
323
00:18:00,060 --> 00:18:01,320
Nikolay: Ah, I see how.
324
00:18:01,320 --> 00:18:05,140
For example, if you try to delete
something without cascade and
325
00:18:05,140 --> 00:18:09,380
it says it cannot be deleted because
there is a row in different
326
00:18:09,380 --> 00:18:14,240
table which we reference to, it
reveals the presence of this
327
00:18:14,240 --> 00:18:17,060
row, but maybe you are not supposed
to see it.
328
00:18:18,760 --> 00:18:20,780
Yeah, you like, it's not your role.
329
00:18:21,100 --> 00:18:23,180
It's somebody else's role.
330
00:18:23,680 --> 00:18:24,920
Something like this, interesting.
331
00:18:24,920 --> 00:18:27,980
Yeah, and then like from error,
you can conclude that there is
332
00:18:27,980 --> 00:18:30,040
some data there, right?
333
00:18:30,100 --> 00:18:32,620
Maybe you can understand the values.
334
00:18:32,980 --> 00:18:33,980
Yeah, it's interesting.
335
00:18:34,120 --> 00:18:36,880
But I never saw such situations
in production.
336
00:18:37,540 --> 00:18:41,860
Another thing I had experience
with is that pg_dump.
337
00:18:42,340 --> 00:18:46,460
Yeah, you mentioned also before
we started recording that it's
338
00:18:46,460 --> 00:18:47,380
bad for backups.
339
00:18:48,580 --> 00:18:52,620
Michael: No, it's not bad, but
you just have to test your backups.
340
00:18:53,200 --> 00:18:55,580
Nikolay: But as I said, the dumps
are not backups.
341
00:18:56,280 --> 00:19:00,600
I'm still on this idea that by
default backup is physical backup.
342
00:19:00,600 --> 00:19:02,580
If we say logical backups, okay.
343
00:19:03,200 --> 00:19:06,560
It's good, it's bad for, I mean
not bad, exactly.
344
00:19:06,620 --> 00:19:11,960
It can be tricky and surprising
for logical backups.
345
00:19:11,960 --> 00:19:16,480
For example, you dump your table
but you see only rows you can
346
00:19:16,480 --> 00:19:16,980
see.
347
00:19:17,520 --> 00:19:18,020
Surprise.
348
00:19:18,240 --> 00:19:19,860
Michael: Yeah, well, exactly.
349
00:19:19,860 --> 00:19:23,320
I was just imagining using a service
like Supabase and wanting
350
00:19:23,320 --> 00:19:29,340
to keep a semi-regular dump of
the data somewhere else just for
351
00:19:29,340 --> 00:19:30,920
my own peace of mind.
352
00:19:31,320 --> 00:19:34,900
Nikolay: No errors, just lack of
a lot of data.
353
00:19:38,100 --> 00:19:41,680
Michael: It was more that if you're
not super careful about which
354
00:19:41,680 --> 00:19:44,800
user you're using, like making
sure that's from a super user
355
00:19:44,800 --> 00:19:49,540
or some role that can see all the
data, it'd be very easy to
356
00:19:49,540 --> 00:19:53,940
think I've got like I've backed
this up and then if you actually
357
00:19:53,940 --> 00:19:57,020
ever need it you're in real trouble
you've lost a lot of data.
358
00:19:57,180 --> 00:19:59,560
Nikolay: Yeah you can have it unnoticed.
359
00:20:00,540 --> 00:20:04,120
Michael: Yeah a credit to the Postgres
documentation They called
360
00:20:04,120 --> 00:20:06,100
that out as something to be aware
of.
361
00:20:06,500 --> 00:20:11,240
Nikolay: In the same area of dumps,
a pg_dump doesn't have skip
362
00:20:11,240 --> 00:20:14,820
policies, or pg_restore doesn't
have skip policies flag, as I
363
00:20:14,820 --> 00:20:15,320
remember.
364
00:20:16,060 --> 00:20:20,360
And this was a problem because
some users of our Database Lab
365
00:20:20,360 --> 00:20:23,100
Engine, DBLab Engine, they...
366
00:20:23,640 --> 00:20:26,920
This is how actually I noticed
that more and more people start
367
00:20:26,920 --> 00:20:28,940
using row level security.
368
00:20:29,480 --> 00:20:32,900
I just like They start asking questions,
okay, we have some low-level
369
00:20:32,900 --> 00:20:36,860
security here, but we restore it
under, like in this non-production
370
00:20:37,080 --> 00:20:39,740
environment for dev test activities.
371
00:20:40,440 --> 00:20:43,940
And we don't need row level security
at all here, right?
372
00:20:44,160 --> 00:20:45,040
How to skip it?
373
00:20:45,040 --> 00:20:48,300
We just want to check various stuff.
374
00:20:49,940 --> 00:20:53,940
And pg_restore has a lot of flags,
to skip this, to skip that,
375
00:20:53,940 --> 00:20:54,740
many things.
376
00:20:55,400 --> 00:20:59,420
But as for policies, skip policies,
it's lacking.
377
00:20:59,700 --> 00:21:05,440
And We needed to deal with feature
supports, hyphen l, small
378
00:21:05,440 --> 00:21:10,440
l, lowercase l and uppercase L,
to have a list of objects present
379
00:21:10,440 --> 00:21:15,860
in the dump, and then just have
filter added, like it's a dictionary
380
00:21:15,920 --> 00:21:19,780
of everything that was dumped,
and we just removed policies and
381
00:21:19,780 --> 00:21:21,220
then restored without them.
382
00:21:21,220 --> 00:21:23,800
And we automated this in the Database
Lab Engine.
383
00:21:23,860 --> 00:21:27,520
So basically, the idea is, if I
had a little bit more time, I
384
00:21:27,520 --> 00:21:30,060
would probably code it and pg_restore
could have it.
385
00:21:30,060 --> 00:21:33,360
It feels like some good addition
for future Postgres versions.
386
00:21:34,060 --> 00:21:38,080
Michael: I understand the attraction,
but I'm also kind of against
387
00:21:38,140 --> 00:21:38,480
it.
388
00:21:38,480 --> 00:21:41,480
Like, partly because we're about
to discuss performance issues,
389
00:21:41,480 --> 00:21:41,980
right?
390
00:21:42,260 --> 00:21:44,020
I'd want to catch those earlier.
391
00:21:44,040 --> 00:21:45,260
I'd want to know.
392
00:21:45,360 --> 00:21:49,600
I'd probably want to still have
row level security on in my dev
393
00:21:49,600 --> 00:21:50,100
environment.
394
00:21:52,040 --> 00:21:53,040
Nikolay: Good point, actually.
395
00:21:53,220 --> 00:21:53,720
Yeah.
396
00:21:54,000 --> 00:21:57,360
Removing policies, this is what
we didn't think about.
397
00:21:57,360 --> 00:22:01,740
We just received idea, let's remove
it, and we implemented it.
398
00:22:01,740 --> 00:22:03,900
Now I think, oh, indeed, you're
right.
399
00:22:04,360 --> 00:22:04,980
You can...
400
00:22:05,900 --> 00:22:07,120
You don't see the whole...
401
00:22:07,200 --> 00:22:11,380
Not plan, but all the problems
that policies can bring and we
402
00:22:11,380 --> 00:22:16,740
will discuss in a minute Maybe
1 of the biggest right about stable
403
00:22:16,740 --> 00:22:21,260
function and so on Yeah, so it's
a good point But it means also
404
00:22:21,260 --> 00:22:25,760
that if you want to have policies,
you want to reconstruct your
405
00:22:25,760 --> 00:22:26,260
users.
406
00:22:26,480 --> 00:22:28,860
Well, this is a good idea as well.
407
00:22:28,860 --> 00:22:31,800
So I have 2 do ideas, 2 to do ideas.
408
00:22:32,520 --> 00:22:35,060
Anyway, skip policies is valid
flag for pg_dump.
409
00:22:35,280 --> 00:22:37,580
In some cases, it's up to the user,
right?
410
00:22:37,580 --> 00:22:39,360
It should be possible to decide.
411
00:22:39,620 --> 00:22:43,600
Because it supports the removal
of skipping of many other things.
412
00:22:44,020 --> 00:22:44,520
True.
413
00:22:44,760 --> 00:22:47,040
Like permissions, for example,
ACL, right?
414
00:22:47,040 --> 00:22:48,980
It's booming, it's skipped.
415
00:22:49,940 --> 00:22:52,620
But ownership, but RLS now.
416
00:22:52,900 --> 00:22:56,780
But I have to do for Database Lab
Engine as well, like we should find
417
00:22:56,780 --> 00:23:02,840
a path to simplify restoration
of users and to preserve all policies
418
00:23:02,980 --> 00:23:04,460
so we see performance.
419
00:23:04,620 --> 00:23:08,300
I mean, this is 1 of the purposes
of the Database Lab Engine, to experiment
420
00:23:08,420 --> 00:23:09,620
with plans, right?
421
00:23:09,620 --> 00:23:13,280
And see how indexes help or not
help, and so on.
422
00:23:13,280 --> 00:23:13,780
Yeah.
423
00:23:13,940 --> 00:23:14,440
Good.
424
00:23:15,040 --> 00:23:16,900
Let's talk about performance, back
to performance.
425
00:23:17,320 --> 00:23:23,720
So we discussed that you must put
this filter from policies.
426
00:23:23,860 --> 00:23:29,200
You must duplicate filtering in
the where clause to achieve good
427
00:23:29,200 --> 00:23:29,700
performance.
428
00:23:30,400 --> 00:23:35,320
Another thing is that it's natural
to use function current_setting,
429
00:23:35,320 --> 00:23:36,790
for example, or something like
this.
430
00:23:36,790 --> 00:23:42,180
Some function which current_setting
is just getting the value
431
00:23:42,180 --> 00:23:44,160
of a variable.
432
00:23:44,240 --> 00:23:50,680
It can be standard GUC, grand unified
configuration, or GUC variables,
433
00:23:50,740 --> 00:23:50,940
right?
434
00:23:50,940 --> 00:23:52,060
Let's call them variables.
435
00:23:52,480 --> 00:23:54,440
Or it can be user defined variable.
436
00:23:54,600 --> 00:23:58,940
It has to have namespace or blah,
blah, dot blah, blah, right?
437
00:23:59,180 --> 00:24:02,640
And you can use in set or set_config
function.
438
00:24:03,040 --> 00:24:04,660
You can set it to something.
439
00:24:05,420 --> 00:24:09,380
And then you can use it, you can
access it either using show,
440
00:24:09,520 --> 00:24:13,680
but you cannot use show inside
SQL query.
441
00:24:13,940 --> 00:24:18,500
To access it inside SQL query,
you can use function current_setting.
442
00:24:19,300 --> 00:24:24,520
And naturally for Postgres, Postgres,
and I think for Hasura
443
00:24:24,520 --> 00:24:28,020
as well, many things are coming
inside these functions already
444
00:24:28,020 --> 00:24:33,500
preset by this thin layer which
provides API.
445
00:24:33,840 --> 00:24:35,780
For example, some headers are there.
446
00:24:36,420 --> 00:24:41,820
And in headers, and also like processing
of JWT tokens, basically,
447
00:24:42,620 --> 00:24:46,220
authentication, authorization is
done through this mechanism.
448
00:24:46,240 --> 00:24:50,980
And it's natural for you to include
it into queries and say,
449
00:24:50,980 --> 00:24:53,900
okay, current_setting and blah,
blah, blah, and we see which
450
00:24:53,900 --> 00:24:57,540
user is working right now.
451
00:25:00,020 --> 00:25:03,740
And Again, it's natural to put the current setting into definition
452
00:25:04,700 --> 00:25:06,780
of your level security policies.
453
00:25:07,360 --> 00:25:13,220
And you say, okay, I don't like customer ID equals what you have
454
00:25:13,340 --> 00:25:17,360
in some headers or something coming from JWT token, anywhere.
455
00:25:17,580 --> 00:25:21,340
And you just use current setting to identify your user and Apply
456
00:25:21,340 --> 00:25:24,560
the security rule to filter out on the rows.
457
00:25:24,640 --> 00:25:29,860
This user can see only right So you have current setting used
458
00:25:29,860 --> 00:25:32,860
in row level security And here we come to 2 problems.
459
00:25:32,960 --> 00:25:36,520
First problem is 2 separate problems, actually, but they are
460
00:25:36,520 --> 00:25:37,020
connected.
461
00:25:38,300 --> 00:25:41,920
First big problem is that if you have select count dealing with
462
00:25:41,920 --> 00:25:46,160
many, many rows, like a million, 10 million, or it may be another
463
00:25:46,160 --> 00:25:46,660
aggregate.
464
00:25:47,020 --> 00:25:49,080
We know Postgres has slow count, right?
465
00:25:49,240 --> 00:25:53,620
But if you have row level security, slow count is order of magnitude
466
00:25:53,620 --> 00:25:59,340
slower, even worse, because row level security check is applied
467
00:25:59,340 --> 00:26:00,220
to each row.
468
00:26:00,940 --> 00:26:01,800
This is terrible.
469
00:26:02,080 --> 00:26:07,760
We already have very slow aggregates, which makes you think even
470
00:26:07,760 --> 00:26:13,200
more about something like materialized views or continuous aggregates
471
00:26:13,520 --> 00:26:18,740
in TimescaleDB or some other stuff, like other kind of pre-calculation,
472
00:26:20,660 --> 00:26:22,260
like denormalization with pre-calculation.
473
00:26:22,440 --> 00:26:24,100
I don't know, like something like this.
474
00:26:24,400 --> 00:26:30,360
So not providing actual values in real time, because It's a huge
475
00:26:30,360 --> 00:26:34,360
penalty, additional check, even if it's just a simple check with
476
00:26:34,360 --> 00:26:35,820
constants and that's it.
477
00:26:36,220 --> 00:26:38,040
This is the number 1 problem.
478
00:26:38,800 --> 00:26:40,900
It feels terrible and I don't have a solution.
479
00:26:40,900 --> 00:26:43,980
We don't have good solutions, actually, honestly, to slow count
480
00:26:43,980 --> 00:26:46,080
in Postgres because it's a row store.
481
00:26:46,520 --> 00:26:51,880
It's really expensive to calculate the sum of 100 million values.
482
00:26:52,860 --> 00:26:56,260
But now we all additionally need to check every row.
483
00:26:57,180 --> 00:26:58,180
Can we deal with it?
484
00:26:58,180 --> 00:26:59,120
Can we deal with it?
485
00:26:59,120 --> 00:27:00,460
Oh, it's not our row.
486
00:27:00,580 --> 00:27:02,060
Wow, it's super slow.
487
00:27:02,440 --> 00:27:07,180
But additionally, another layer of penalty comes if you use a
488
00:27:07,180 --> 00:27:11,660
function which is not immutable, which is stable, for example,
489
00:27:11,660 --> 00:27:13,280
or volatile, which is worse.
490
00:27:13,680 --> 00:27:15,600
But current setting is stable function.
491
00:27:16,780 --> 00:27:21,720
It means that Postgres also, even with its current setting and
492
00:27:21,720 --> 00:27:27,160
just some variable which is just set and that's it, it will call
493
00:27:27,160 --> 00:27:28,440
it for each row.
494
00:27:28,700 --> 00:27:29,880
Boom, boom, boom.
495
00:27:29,900 --> 00:27:30,400
Right?
496
00:27:31,260 --> 00:27:33,160
And this is insanely slow already.
497
00:27:33,340 --> 00:27:34,300
Insanely slow.
498
00:27:36,200 --> 00:27:40,120
So people can think Postgres has slow count.
499
00:27:40,920 --> 00:27:43,940
People with RLS can think, oh, it's very slow count.
500
00:27:43,940 --> 00:27:48,940
People with RLS and current setting inside RLS think, okay, it's
501
00:27:48,940 --> 00:27:49,840
terribly slow.
502
00:27:49,840 --> 00:27:51,420
Absolutely terribly slow, right?
503
00:27:52,120 --> 00:27:56,320
Yeah, but for this last problem
with current_setting, there is
504
00:27:56,320 --> 00:28:00,520
a few ways to avoid this behavior.
505
00:28:02,020 --> 00:28:07,540
I like the way just to put it inside
parentheses and write SELECT
506
00:28:07,540 --> 00:28:08,040
word.
507
00:28:08,400 --> 00:28:14,340
So Postgres Planner moves current_setting call into, it's called
508
00:28:14,340 --> 00:28:17,420
init plan, right?
509
00:28:18,180 --> 00:28:22,120
Another node in the plan, and it
will be called once, and then
510
00:28:22,120 --> 00:28:22,840
just used.
511
00:28:22,840 --> 00:28:23,580
That's great.
512
00:28:23,680 --> 00:28:25,020
So this is easy solution.
513
00:28:25,600 --> 00:28:27,600
Just surround by parentheses and...
514
00:28:28,740 --> 00:28:30,920
Just surrounded by parentheses
won't solve it.
515
00:28:30,920 --> 00:28:32,300
You need the word SELECT.
516
00:28:32,360 --> 00:28:35,380
So it becomes sub SELECT that goes
to a new plan.
517
00:28:35,380 --> 00:28:36,960
This is also interesting behavior.
518
00:28:37,340 --> 00:28:39,560
Also quite surprising to some folks.
519
00:28:40,080 --> 00:28:42,320
But anyway, there is some solution
here.
520
00:28:42,840 --> 00:28:48,900
However, problem like we need to
check every row in real time,
521
00:28:49,940 --> 00:28:51,300
it cannot go away.
522
00:28:51,820 --> 00:28:56,180
This is actually the number 1,
maybe the only 1 reason I think
523
00:28:56,180 --> 00:28:59,940
RLS, row level security is painful.
524
00:29:00,740 --> 00:29:02,720
Like how to solve it?
525
00:29:03,920 --> 00:29:09,240
Michael: I was reading the, there's
a really good gist put together
526
00:29:09,240 --> 00:29:13,660
by I think 1 of the team at Supabase and or at least they reference
527
00:29:13,660 --> 00:29:20,560
it in their docs. And they do mention
a kind of a trick where
528
00:29:20,560 --> 00:29:26,840
if as long as the function isn't
leaking any information, you
529
00:29:26,840 --> 00:29:28,760
could bypass RLS.
530
00:29:28,980 --> 00:29:32,320
So you can, I think it's called
security definer?
531
00:29:32,800 --> 00:29:36,760
You can set it up in a way that
the function can then bypass
532
00:29:36,900 --> 00:29:37,940
row level security.
533
00:29:39,720 --> 00:29:40,380
But yeah,
534
00:29:40,380 --> 00:29:43,240
Nikolay: I- But it feels like we're
turning off.
535
00:29:43,860 --> 00:29:44,260
Why?
536
00:29:44,260 --> 00:29:49,720
I can say, OK, let's run all massive
aggregate calls, like counts,
537
00:29:49,960 --> 00:29:51,240
sums, anything.
538
00:29:51,540 --> 00:29:55,820
Let's just run them using a User
which bypasses RLS.
539
00:29:56,920 --> 00:29:57,680
That's it.
540
00:29:58,660 --> 00:30:02,020
If you want to present some big
count somewhere, just do this.
541
00:30:02,020 --> 00:30:07,080
But if it's global it makes sense,
I would say okay here we need
542
00:30:07,080 --> 00:30:10,680
to count everything bypass RLS, we would do it anyway.
543
00:30:10,680 --> 00:30:16,120
But if it's inside single organization
it feels like breaking
544
00:30:16,120 --> 00:30:18,620
a hole in our wall we just built.
545
00:30:19,120 --> 00:30:23,440
Michael: I don't understand it
enough to understand why that
546
00:30:23,440 --> 00:30:25,840
might be okay and I think you would
have to be careful about
547
00:30:25,840 --> 00:30:29,220
not leaking information but because
of that first tip where we're
548
00:30:29,220 --> 00:30:33,040
still providing all the where clauses
we need to only be accessing
549
00:30:33,040 --> 00:30:35,640
that organization at the query
level.
550
00:30:36,100 --> 00:30:39,220
We've still got 1 level of security
there.
551
00:30:39,960 --> 00:30:44,300
So I can see why it's attractive,
but that's the only solution
552
00:30:44,300 --> 00:30:49,660
I saw to avoid doing it on every,
to avoid that check.
553
00:30:49,660 --> 00:30:51,000
Nikolay: It's logical problem.
554
00:30:51,220 --> 00:30:57,600
If we must definitely check, and
we do it after the player already
555
00:30:57,600 --> 00:31:01,380
did everything, and basically after
the last stage of execution,
556
00:31:01,400 --> 00:31:01,900
right?
557
00:31:03,480 --> 00:31:08,600
It's going to be super expensive
if you have a lot of rows before
558
00:31:08,600 --> 00:31:10,120
producing the final result.
559
00:31:10,920 --> 00:31:16,120
But I feel kind of like Postgres
could say, okay, we have it
560
00:31:16,520 --> 00:31:19,540
in the workloads, we already applied
this rule, let's skip it.
561
00:31:19,540 --> 00:31:22,500
This could be some optimization,
but it needs to be done inside
562
00:31:22,500 --> 00:31:24,300
Postgres somehow.
563
00:31:24,720 --> 00:31:26,520
I'm not sure if it was discussed.
564
00:31:26,520 --> 00:31:30,280
Michael: Well, like all planner
things, it would work, even if
565
00:31:30,280 --> 00:31:33,680
it was implemented for simple conditions,
it wouldn't work for
566
00:31:33,680 --> 00:31:34,620
some more complex.
567
00:31:35,220 --> 00:31:39,160
There would be a never-ending list
of quick, because these policies
568
00:31:39,160 --> 00:31:39,960
are so flexible.
569
00:31:39,960 --> 00:31:41,320
That's 1 of their strengths, right?
570
00:31:41,320 --> 00:31:43,980
You can set pretty much anything
as a policy.
571
00:31:43,980 --> 00:31:46,320
You can do it at the operation
level.
572
00:31:46,320 --> 00:31:49,900
You can do it at a role level,
you do so many different levels,
573
00:31:49,900 --> 00:31:52,940
and then you can pretty much, I
think you can use any SQL query
574
00:31:53,320 --> 00:31:55,760
to set up exactly the policy you
want.
575
00:31:55,760 --> 00:31:56,260
Nikolay: Yeah.
576
00:31:56,580 --> 00:31:59,380
Michael: Then you've got a whole
new planning issue, like the
577
00:31:59,380 --> 00:32:03,020
planners are already pretty complicated,
So I get why they haven't.
578
00:32:04,060 --> 00:32:04,720
Nikolay: I agree.
579
00:32:06,040 --> 00:32:09,560
For example, you know, in the check
constraints, you cannot refer
580
00:32:09,560 --> 00:32:10,460
to other tables.
581
00:32:14,380 --> 00:32:15,300
They are simple.
582
00:32:16,400 --> 00:32:21,380
But here in these policies, like
rules, we can do whatever we
583
00:32:21,380 --> 00:32:21,880
want.
584
00:32:21,980 --> 00:32:25,180
This means it's super, like what
I just proposed, probably it's
585
00:32:25,180 --> 00:32:26,820
impossible to implement, right?
586
00:32:27,060 --> 00:32:30,760
If it was just this table, no reference
to other table, Maybe
587
00:32:30,760 --> 00:32:34,640
current setting can be used and
the seat maybe there would be
588
00:32:34,640 --> 00:32:38,560
a way to Connect to the planner
and see okay.
589
00:32:38,560 --> 00:32:42,080
It's already applied this rule
that we can skip it Skip it in
590
00:32:42,080 --> 00:32:47,160
a safe manner 100% safe man reliable
manner, but if we can refer
591
00:32:47,160 --> 00:32:50,340
to any table write anything there
it's impossible
592
00:32:52,200 --> 00:32:53,720
Michael: or much more
593
00:32:53,720 --> 00:32:58,820
Nikolay: so many like predicates
like yeah so I agree with you
594
00:32:58,820 --> 00:32:59,320
here
595
00:32:59,760 --> 00:33:02,300
Michael: there's for people that
want that I will share I'll
596
00:33:02,300 --> 00:33:05,460
share a link to that gist there's
also a really good talk by
597
00:33:05,900 --> 00:33:09,820
Paul Copplestone, CEO of Supabase
from the last POSETTE conference
598
00:33:09,820 --> 00:33:13,580
I can share as well does a beginner's
guide to RLS but also covers
599
00:33:13,580 --> 00:33:17,100
some quite in-depth manages to
in about 20 minutes cover some
600
00:33:17,100 --> 00:33:19,920
quite in-depth performance tips
I think most of which we've covered
601
00:33:19,920 --> 00:33:22,800
now, but it's visual and you can
see him going through them,
602
00:33:22,800 --> 00:33:23,420
which is nice.
603
00:33:23,420 --> 00:33:23,800
Nikolay: Yeah.
604
00:33:23,800 --> 00:33:30,260
Well, I'm quite sure, like Supabase
and other systems which
605
00:33:30,300 --> 00:33:36,700
work with Postgres or Hasura or
something, these guys are at
606
00:33:36,700 --> 00:33:40,240
the frontier of RLS usage, right?
607
00:33:40,240 --> 00:33:45,740
And for sure a lot of experience
is in the discussions there,
608
00:33:46,980 --> 00:33:47,820
which is great.
609
00:33:48,800 --> 00:33:55,020
But I just see, still I feel like
we already had bad Aggregates
610
00:33:55,440 --> 00:33:59,620
you you made them worse Starting
starting using RLS.
611
00:33:59,620 --> 00:34:02,260
So yeah So By the
612
00:34:02,260 --> 00:34:03,873
Michael: way, I had a question
for you.
613
00:34:03,873 --> 00:34:07,940
Did you know how many times we've
had this topic requested for
614
00:34:07,940 --> 00:34:08,540
the podcast?
615
00:34:08,940 --> 00:34:10,020
Nikolay: I have no idea.
616
00:34:11,040 --> 00:34:11,780
Michael: 4 times.
617
00:34:12,180 --> 00:34:14,600
4 different people have requested
something.
618
00:34:15,780 --> 00:34:18,740
That's by far the most we've ever
had for a single topic.
619
00:34:19,540 --> 00:34:22,900
Nikolay: Okay, in this case we
should have a lot of feedback,
620
00:34:23,500 --> 00:34:24,140
I guess.
621
00:34:24,140 --> 00:34:24,640
Well,
622
00:34:25,080 --> 00:34:25,580
Michael: yeah.
623
00:34:25,940 --> 00:34:29,800
There are also a couple of people
asking about, like, when asked
624
00:34:29,800 --> 00:34:32,680
for more information, like what
exactly they wanted us to talk
625
00:34:32,680 --> 00:34:32,960
about.
626
00:34:32,960 --> 00:34:36,040
They asked about considerations
around performance, like how
627
00:34:36,040 --> 00:34:39,280
to then diagnose performance issues,
but I don't think there's
628
00:34:39,280 --> 00:34:40,760
anything unique about it, right?
629
00:34:40,760 --> 00:34:42,780
Like mostly it's still...
630
00:34:43,260 --> 00:34:44,520
Whoa, it's tricky,
631
00:34:44,640 --> 00:34:45,920
Nikolay: it's tricky, yeah.
632
00:34:46,020 --> 00:34:51,060
My, like, general rule is just
to compare with and without RLS
633
00:34:52,640 --> 00:34:55,940
For example, you can use user spaces.
634
00:34:55,960 --> 00:34:56,460
Yeah.
635
00:34:56,640 --> 00:35:00,560
Yeah, because it can be tricky
I of course you like filter and
636
00:35:00,560 --> 00:35:04,600
so on but I feel like in the plans
or maybe I'm missing something
637
00:35:04,600 --> 00:35:09,320
but I feel in the plans where like
we can start guessing how
638
00:35:09,320 --> 00:35:11,820
much time do we spend on an RLS
check.
639
00:35:12,640 --> 00:35:16,320
Michael: I well I think I think
personally if you're if you've
640
00:35:16,320 --> 00:35:19,940
already gone with RLS if you've
already decided that and you're
641
00:35:19,940 --> 00:35:24,640
well into your project, I think
the RLS checks don't matter that
642
00:35:24,640 --> 00:35:24,960
much.
643
00:35:24,960 --> 00:35:26,020
It's more indexing.
644
00:35:26,760 --> 00:35:31,280
I still see more people with indexing
issues than RLS performance
645
00:35:31,320 --> 00:35:31,820
issues.
646
00:35:32,540 --> 00:35:36,480
They look like RLS issues because
people might think that...
647
00:35:36,600 --> 00:35:37,280
I agree,
648
00:35:37,280 --> 00:35:37,800
Nikolay: I agree.
649
00:35:37,800 --> 00:35:42,760
But I'm talking about this massive
count, for example, like,
650
00:35:42,800 --> 00:35:46,720
you have a count on them and how
much of that time, like, how
651
00:35:46,720 --> 00:35:49,840
much, how big is the overhead from
our list?
652
00:35:49,840 --> 00:35:52,960
It's quite tricky without like
comparing 2 cases.
653
00:35:54,020 --> 00:35:58,680
I wish the EXPLAIN ANALYZE show
this.
654
00:35:58,680 --> 00:36:05,180
By the way, We just have BUFFERS
by default committed, right?
655
00:36:05,540 --> 00:36:07,840
We forgot to celebrate a little
bit.
656
00:36:07,840 --> 00:36:09,960
Maybe it should be a separate episode
about this.
657
00:36:09,960 --> 00:36:10,240
I don't
658
00:36:10,240 --> 00:36:10,380
Michael: know.
659
00:36:10,380 --> 00:36:14,960
I think I want to wait until Postgres
18 to celebrate that, or
660
00:36:14,960 --> 00:36:17,640
at least far into the future to
release candidates.
661
00:36:17,640 --> 00:36:19,040
Nikolay: I cannot believe this.
662
00:36:19,540 --> 00:36:20,720
It's super great, right?
663
00:36:21,400 --> 00:36:23,720
Michael: Yeah, a couple of things
people to thank on that front.
664
00:36:23,720 --> 00:36:28,680
I think David Rowley did a really
good job and also Guillaume
665
00:36:28,680 --> 00:36:32,060
Lellouche did a lot of the heavy
lifting as well.
666
00:36:32,180 --> 00:36:34,800
So those 2 in particular, there
was a really good conversation
667
00:36:34,840 --> 00:36:37,380
on the mailing list that I think
you kicked off actually.
668
00:36:38,400 --> 00:36:41,240
Nikolay: I didn't expect at this
time it will go through.
669
00:36:42,720 --> 00:36:45,580
I was discussing things near this
topic, right?
670
00:36:46,060 --> 00:36:50,540
But I'm happy to see it and I guess
I will need to find another
671
00:36:50,540 --> 00:36:52,760
topic to be upset with.
672
00:36:53,400 --> 00:36:57,940
Because it was more than 2 years
I was talking about how I'm
673
00:36:57,940 --> 00:37:00,040
upset that BUFFERS are not default.
674
00:37:00,720 --> 00:37:02,340
And it's going to be over.
675
00:37:02,980 --> 00:37:08,860
I feel happy and sad at the same
time Another thing was UUID
676
00:37:08,860 --> 00:37:15,140
version 7 finally Right, and you
know what like my perception
677
00:37:15,360 --> 00:37:20,560
was we were waiting until full
finalization of RFC, right?
678
00:37:21,180 --> 00:37:22,480
Michael: Oh, I forgot to say too.
679
00:37:22,660 --> 00:37:23,980
Nikolay: Yeah, because everyone...
680
00:37:24,140 --> 00:37:25,147
Michael: Is it not being finalized?
681
00:37:25,147 --> 00:37:28,640
Nikolay: It was developed before
Postgres 17 released and then
682
00:37:29,040 --> 00:37:33,080
the decision was made not to take
it into 17 because RFC is not
683
00:37:33,080 --> 00:37:33,980
fully finalized.
684
00:37:34,200 --> 00:37:38,300
At the same time, everyone already
started releasing UUID support
685
00:37:38,300 --> 00:37:43,380
like Node.js, Go, like Google decided
to release it, everyone
686
00:37:43,380 --> 00:37:45,460
already, but Postgres decided to stay
conservative.
687
00:37:45,700 --> 00:37:51,140
The thing is that, unless I'm fully
mistaken, I see RFC is not
688
00:37:51,140 --> 00:37:52,720
fully finalized yet.
689
00:37:53,400 --> 00:37:53,560
Michael: Amazing.
690
00:37:53,560 --> 00:37:54,060
Still.
691
00:37:54,840 --> 00:37:57,340
So maybe it will be before 18's
released?
692
00:37:57,340 --> 00:38:01,160
Nikolay: Andrey told me not to
shout about this.
693
00:38:02,220 --> 00:38:03,000
Michael: Probably sensible.
694
00:38:03,280 --> 00:38:07,940
Andrey and I have similar philosophies
then, wait until it's
695
00:38:07,940 --> 00:38:09,580
actually released before celebrating.
696
00:38:09,580 --> 00:38:12,520
Nikolay: Yeah I bet we can talk
about these things here because
697
00:38:12,520 --> 00:38:14,820
hackers don't listen to us right
so.
698
00:38:14,840 --> 00:38:16,360
Michael: I think a couple days.
699
00:38:16,940 --> 00:38:20,060
Nikolay: They won't go and say
let's revert it I hope.
700
00:38:20,240 --> 00:38:25,680
Anyway congrats to Andrey because
this is who coded it, This
701
00:38:25,680 --> 00:38:29,600
is him who coded this during our Postgres TV live coding, hacking
702
00:38:29,600 --> 00:38:32,000
sessions with Kirk and Andrey.
703
00:38:32,140 --> 00:38:36,880
So yeah, this week was, to commit, surprised me.
704
00:38:37,360 --> 00:38:41,600
Both things I'm like very passionate about, like buffers by default
705
00:38:41,600 --> 00:38:47,080
in Explain, Analyze, and UID version 7, I think, again, like
706
00:38:47,080 --> 00:38:50,640
people who listen to us, don't wait until the release of those
707
00:38:51,140 --> 00:38:56,100
functions, UUIDv7, start using it right now because it's just,
708
00:38:56,100 --> 00:38:57,680
basically, it's synthetic sugar.
709
00:38:57,800 --> 00:39:02,960
Not fully, but you can start using UUID data type and insert
710
00:39:02,960 --> 00:39:07,660
UUID version 7 generated on application side, or using some SQL
711
00:39:07,660 --> 00:39:09,220
function, PGSQL function.
712
00:39:09,220 --> 00:39:10,780
I have examples in my how-tos.
713
00:39:11,640 --> 00:39:15,940
And when this feature becomes native, switch to native.
714
00:39:16,400 --> 00:39:21,820
But it's hard to overestimate the importance of this support
715
00:39:21,820 --> 00:39:25,440
because you know I can convince a couple of guys to start using
716
00:39:25,440 --> 00:39:26,180
right now.
717
00:39:26,180 --> 00:39:31,440
Some guys can guess but 90% will follow default path right?
718
00:39:31,920 --> 00:39:32,920
Michael: Same with buffers.
719
00:39:34,020 --> 00:39:34,520
Nikolay: Exactly.
720
00:39:35,140 --> 00:39:37,280
Michael: People can start using it now, there's no reason they
721
00:39:37,280 --> 00:39:40,440
can't use it now, it's just more will once it's there.
722
00:39:40,440 --> 00:39:43,780
Nikolay: We will finally analyze plans with buffers always and
723
00:39:43,780 --> 00:39:50,160
let's like to wrap it up, when you see overhead from RLS, it's
724
00:39:50,160 --> 00:39:52,160
not about buffers, usually.
725
00:39:52,540 --> 00:39:55,060
Unless it's a lack of index.
726
00:39:55,640 --> 00:39:59,320
But if this is like current setting, we talked about current
727
00:39:59,320 --> 00:40:01,600
setting on each row, it's called.
728
00:40:02,620 --> 00:40:06,540
Buffers are like tiny, but timing is awful.
729
00:40:07,880 --> 00:40:11,300
And yeah, this is 1 of the rare cases where buffers...
730
00:40:11,760 --> 00:40:13,260
Well, buffers don't lie, right?
731
00:40:13,260 --> 00:40:14,160
They don't lie.
732
00:40:14,220 --> 00:40:15,720
They show there is no I/O
733
00:40:15,720 --> 00:40:16,220
Here.
734
00:40:16,400 --> 00:40:17,980
And it's already useful information.
735
00:40:18,560 --> 00:40:19,060
But...
736
00:40:19,340 --> 00:40:20,420
Michael: But you need both.
737
00:40:21,020 --> 00:40:22,100
Nikolay: You need both, right.
738
00:40:22,100 --> 00:40:26,840
And you know, sometimes I say, most of the time we optimize targeting
739
00:40:26,840 --> 00:40:27,340
buffers.
740
00:40:27,400 --> 00:40:32,140
In this case, we don't because it's just not about I/O
741
00:40:32,140 --> 00:40:32,780
at all.
742
00:40:32,960 --> 00:40:34,340
But seeing that I/O
743
00:40:34,340 --> 00:40:36,720
is low, it already gives us idea.
744
00:40:37,420 --> 00:40:39,040
Maybe it's RLS, right.
745
00:40:40,160 --> 00:40:41,020
Michael: Nice 1, Nikolay.
746
00:40:41,680 --> 00:40:44,320
Well, thanks again and catch you soon.
747
00:40:44,760 --> 00:40:46,640
Nikolay: See you later, bye bye, thank you.