WEBVTT 00:00.000 --> 00:29.600 I think we should be ready to go, wherever's up first. 00:29.600 --> 00:30.600 I'm still clipping. 00:30.600 --> 00:33.400 Actually, I might have to hold this because I think the audio doesn't work that well in this 00:33.400 --> 00:34.400 room. 00:34.400 --> 00:35.400 So hold on a second. 00:35.400 --> 00:36.400 All right. 00:36.400 --> 00:42.000 So, hey everybody, my name is Ben, so I'm going to kick us off with this talk. 00:42.000 --> 00:46.200 So yeah, like I said, myself, I'm going to talk first and talk a little bit about post 00:46.200 --> 00:50.120 stress in my sequel and the whole theme of this next hour is kind of the differences in 00:50.120 --> 00:55.120 the pros and cons and sort of where like cross-pollination between some of the concepts and architectures 00:55.120 --> 00:59.280 of these two databases could help the other communities. 00:59.680 --> 01:03.480 Who here uses post-gress on a regular basis or builds it? 01:03.480 --> 01:04.880 Who here loves my sequel? 01:04.880 --> 01:05.880 Okay, great. 01:05.880 --> 01:09.000 So this is the perfect audience for this kind of talk. 01:09.000 --> 01:13.960 The component and what I had proposed to talk about is titled what I miss about my 01:13.960 --> 01:17.760 sequel, but I'm not just going to talk about my sequel or we're all going to be talking 01:17.760 --> 01:22.800 about both of these wonderful databases, but the reason why I phrased it this way has to 01:22.800 --> 01:27.600 do a little bit with sort of the background of both myself and kind of as a company I'm 01:27.600 --> 01:33.040 with a planet scale and a lot of the background has to do with historically we're known 01:33.040 --> 01:38.000 as a company that runs my sequel as well as the tests and who here's familiar with what 01:38.000 --> 01:41.360 the test is less hands but we have some. 01:41.360 --> 01:46.760 So this is essentially a charting and a scaling and acts as a proxy that sits in front of 01:46.760 --> 01:51.840 my sequel for kind of helping with high-scale my sequel deployments, right? 01:51.840 --> 01:55.920 And so we have a lot of experience throughout the company, like personally my first database 01:55.920 --> 01:59.160 that I ever ran and operated was a my sequel database. 01:59.160 --> 02:03.120 And so there's a lot of things where we have a lot of comfort with this, right? 02:03.120 --> 02:08.320 But one of the things that probably a lot of people in this room recognize myself included 02:08.320 --> 02:13.640 is that over the years postgres has become more and more widely used specifically being 02:13.640 --> 02:15.520 adopted by like bigger companies, right? 02:15.520 --> 02:20.080 Running very large high-scale instances of postgres and a lot of you have probably seen 02:20.080 --> 02:22.200 graphs that look like this before. 02:22.200 --> 02:25.080 Many of you have probably been to dvngens.com before. 02:25.080 --> 02:30.000 And of course you can argue with how they're measuring it and you know, is this actually 02:30.000 --> 02:34.480 accurately representing what the industry is doing, but both based on kind of some of the 02:34.480 --> 02:40.120 data that you can collect as well as just some of the sense that I get from talking to 02:40.120 --> 02:44.240 companies that are running these databases is that postgres is very clearly becoming 02:44.240 --> 02:47.080 more and more widely adopted, right? 02:47.080 --> 02:50.520 Even though my sequel obviously still powers much of the internet and much of what we do 02:50.520 --> 02:52.640 every day. 02:52.640 --> 03:00.240 So as a company, we started doing and running postgres for companies just this past year. 03:00.240 --> 03:03.680 And we're also working on Niki, we have some of the maintainers here who will be talking 03:03.680 --> 03:07.960 a little bit later, but about doing this in production for other companies too. 03:07.960 --> 03:12.400 So it's an interesting perspective coming from someone who's very familiar with my sequel 03:12.400 --> 03:16.720 and as a company very familiar with my sequel, this kind of enter into the postgres space 03:16.720 --> 03:20.520 and see where they're maybe doing things better, but also where there's certain things 03:20.520 --> 03:21.520 like I said. 03:21.520 --> 03:26.440 I miss about my sequel where it has some more maturity and some nice things about it, 03:26.440 --> 03:29.440 which is what we're going to talk about here. 03:29.440 --> 03:34.640 So before I get into a couple of technical things, I want to talk about just why postgres. 03:34.640 --> 03:38.360 And I'm sure throughout the room, we have different people that have different opinions 03:38.360 --> 03:44.080 about why postgres is being adopted, why people choose postgres over my sequel or vice 03:44.080 --> 03:46.680 first in different instances. 03:46.680 --> 03:50.360 So I think one of the reasons and this is coming from my perspective and a lot of the things 03:50.400 --> 03:53.120 that I've observed is just an increasing maturity, right? 03:53.120 --> 03:57.760 If you look over the past decade or maybe a little bit more, the amount of features and 03:57.760 --> 04:02.280 capabilities that have come to postgres have like expanded and in some sense almost like 04:02.280 --> 04:08.120 caught up in some aspects to where my sequel is at, part of it too is the licensing, right? 04:08.120 --> 04:14.360 The postgres license very easy for people to fork, build their own features out, right? 04:14.360 --> 04:19.440 There's the extension ecosystem and just being able to sort of more quickly bring in 04:19.440 --> 04:21.240 the interesting new technology. 04:21.240 --> 04:27.000 So for example, one of my, I did a bunch of benchmarking recently on the postgres 18, like IOU 04:27.000 --> 04:28.640 ring and async IOU support, right? 04:28.640 --> 04:32.120 And this is something that I think is very cool that that was brought to postgres, or is 04:32.120 --> 04:35.360 that something that isn't really as far to my knowledge apart of my sequel yet, right? 04:35.360 --> 04:39.320 So the ability for the postgres community to kind of adopt some of these technologies 04:39.320 --> 04:44.680 and bring them in has been really cool to see that like pace that the postgres contributions 04:44.680 --> 04:48.160 come at. 04:48.160 --> 04:52.720 For those of you who aren't that well versed in the my sequel or in the postgres ecosystem, 04:52.720 --> 04:57.600 there's a huge number of extensions that allow it to kind of increase its capabilities 04:57.600 --> 05:02.920 or perhaps paper over some of the weaknesses that postgres has relative to my sequel, right? 05:02.920 --> 05:06.960 So if you need vector support, if you need kind of advanced geographic information 05:06.960 --> 05:12.320 systems, PG vector, post GIS, there's things like PG squeeze and PG repack that help with 05:12.320 --> 05:14.840 some of the table-blote issues of postgres. 05:14.840 --> 05:19.240 So I think one of the reasons why it's been adopted is because even if you look at postgres 05:19.240 --> 05:23.200 and say, well maybe it's missing certain things or it doesn't fully meet what I need 05:23.200 --> 05:28.200 for my application, there's so many opportunities to build in exactly what you need, or 05:28.200 --> 05:32.480 the other perspective that I have is as a company for example planet scale. 05:32.480 --> 05:35.880 When we started offering postgres one of the things that we wanted to provide is like 05:35.880 --> 05:41.040 a really detailed set of analytics, because this is what our customers are used to running 05:41.080 --> 05:45.200 the test and we give them a lot of insights into like query performance and a lot of details 05:45.200 --> 05:46.200 there. 05:46.200 --> 05:51.160 So we built out a custom extension because postgres didn't provide these APIs to get all 05:51.160 --> 05:55.400 of the query latency data that we needed out of the box and it was very easy for us to 05:55.400 --> 05:58.440 add that in as a feature in postgres, right? 05:58.440 --> 06:04.360 So the extension ecosystem and also you know this is maybe depending on who you are, 06:04.360 --> 06:07.680 what your background is, not something that you're doing all the time as open source 06:07.680 --> 06:12.680 contributors, but in my role I talk to a lot of small companies that are starting out 06:12.680 --> 06:16.800 and they're choosing their text acts kind of what to build on from the ground up. 06:16.800 --> 06:22.080 And if you go back in time maybe 10 or 15, 20 years, my SQL is basically the default choice 06:22.080 --> 06:23.080 all the time, right? 06:23.080 --> 06:25.080 Like that's kind of just what everybody used. 06:25.080 --> 06:29.240 If you needed a relational database you were using my SQL, whereas the story has definitely 06:29.240 --> 06:30.240 changed. 06:30.240 --> 06:36.680 Where a lot of the default choices for what companies are building things on is mostly postgres, 06:36.680 --> 06:37.680 right? 06:37.680 --> 06:41.320 Unless people happen to have a lot of my SQL expertise, there is so much energy behind 06:41.320 --> 06:46.120 the postgres community, which is why the last thing I put on here is also just vibes. 06:46.120 --> 06:49.360 There's a lot of people that are not necessarily choosing it because they've done a 06:49.360 --> 06:55.160 deep analysis of both databases, but simply because this is where what they're recommended, 06:55.160 --> 06:56.160 right? 06:56.160 --> 06:59.240 What other people that they know are using, where there happens to be expertise? 06:59.240 --> 07:04.440 Okay, so getting into a little bit more of the technical side of things, what I've kind 07:04.440 --> 07:07.880 of wanted to think about is like, okay, I look at these two databases. 07:07.880 --> 07:12.120 And I see obviously if you drill into the details, there's hundreds of little differences 07:12.120 --> 07:16.360 in terms of feature sets in terms of the settings and the capabilities of each, but you 07:16.360 --> 07:21.520 can kind of buck it the different capabilities and pros and cons of each of these databases 07:21.520 --> 07:25.720 into what I've picked as kind of six broad categories here. 07:25.720 --> 07:28.160 And by the way, I love both of these databases. 07:28.160 --> 07:31.640 So in doing this comparison and throughout some of the other speakers that are going to talk 07:31.640 --> 07:36.280 about the differences between these two, it isn't about, well, one sucks and one is great. 07:36.280 --> 07:40.360 It's just about being able to kind of expose what the strengths and weaknesses of these 07:40.360 --> 07:43.560 are because it's very interesting to study. 07:43.560 --> 07:48.920 So what I'm not going to talk about in the next seven minutes that I have is clustered indexes 07:48.920 --> 07:52.800 versus the keep storage of postgres and replication because our other speakers are going 07:52.800 --> 07:56.520 to take deeper dives into those after me, kind of kind of flowing into some deep dives 07:56.520 --> 07:58.520 of those concepts. 07:58.520 --> 08:02.720 So I want to focus on these other two, but I'm also not going to focus all that much 08:02.720 --> 08:05.400 on indexing flexibility and extensibility. 08:05.400 --> 08:08.880 And I'm sorry that red color is really hard to see on these slides. 08:08.880 --> 08:12.840 And the reason why I'm not focusing on those is because the perspective of this talk 08:12.840 --> 08:19.200 is mostly what I think my sequel has strengths of that I wish I could see more of in postgres. 08:19.200 --> 08:23.440 And it's because for these other two, in my opinion, there's a lot more indexing flexibility 08:23.440 --> 08:24.680 in postgres. 08:24.720 --> 08:29.680 So it kind of has some advantages there and the extension ecosystem is very mature 08:29.680 --> 08:30.680 in postgres. 08:30.680 --> 08:35.240 So I want to focus on the process versus thread architecture, which probably a lot of you, 08:35.240 --> 08:39.960 especially if you're familiar with these two databases, know about, and the storage engine. 08:39.960 --> 08:43.840 And we're going to have to go through these quickly due to the time. 08:43.840 --> 08:49.400 So who here's familiar with the differences between postgres process per connection architecture 08:49.400 --> 08:51.360 and my sequel thread per connection architecture? 08:51.400 --> 08:55.280 Is this something, I'm sure, good amount of people in the room are, but we have some less familiar. 08:55.280 --> 08:59.200 So the way that postgres works is every time you open a connection to it, postgres is 08:59.200 --> 09:02.880 forking a new process of postgres for that connection. 09:02.880 --> 09:07.080 Versus in my sequel, we get a thread per connection and there's also like a thread 09:07.080 --> 09:09.520 cache or thread pool that it can utilize. 09:09.520 --> 09:14.840 So the in short without jumping into too much detail of it, every connection is heavier 09:14.840 --> 09:16.040 weight in postgres. 09:16.040 --> 09:20.720 Both the time that it takes to establish that connection as well as, you know, context 09:20.720 --> 09:25.360 switching and the memory overheads and having their own virtual memory spaces per connection. 09:25.360 --> 09:30.280 So this makes for, in some sense, the architecture is very nice and convenient in terms 09:30.280 --> 09:34.160 of engineering and it's very nice isolation between connections. 09:34.160 --> 09:38.720 But this also means that for really high concurrency databases, you can run into some 09:38.720 --> 09:39.840 performance issues, right? 09:39.840 --> 09:44.720 Because all of the context switching in the overhead of every connection is very high. 09:44.720 --> 09:50.680 So one of the kind of challenges that I have observed a lot of companies run into, 09:50.680 --> 09:55.200 is when you try to scale up postgres a single instance to be doing a really high number 09:55.200 --> 10:01.320 of connections, there's issues with contention and performance there. 10:01.320 --> 10:05.880 Whereas in my sequel, although you still can encounter some of those things that doesn't 10:05.880 --> 10:09.520 become an issue until further along with a higher number of connections. 10:09.520 --> 10:13.520 So the solution to this is generally connection pooling, right? 10:13.520 --> 10:17.240 We've probably a lot of us, if you've operated databases, you've run some kind of connection 10:17.240 --> 10:21.400 pooler, postgres, PG-Bouncer is a very popular option. 10:21.400 --> 10:27.480 But this is something that we recommend that basically every connection on postgres, if 10:27.480 --> 10:30.120 you can, should go through something like PG-Bouncer, right? 10:30.120 --> 10:34.040 So that you can have, you don't have to re-establish connections with scram, which has 10:34.040 --> 10:38.320 a lot of overhead, you can keep your set of direct connections to postgres that are very 10:38.320 --> 10:42.360 fixed, controllable size, that you know, performs well based on whatever hardware you're 10:42.360 --> 10:47.200 running the database on, and then you can run all connections through a pooler, right? 10:47.200 --> 10:50.960 And so this is one of the things where, like I said, what do I miss about my sequel? 10:50.960 --> 10:56.320 I like the way that my sequel handles high number of connection counts and the concurrency 10:56.320 --> 10:57.880 control there, right? 10:57.880 --> 11:01.680 And this is something too that this also ties in a little bit with how the storage engine 11:01.680 --> 11:05.560 handles multi-version concurrency control and transactions, which will be the next talk 11:05.560 --> 11:07.800 here. 11:07.800 --> 11:11.680 And then the one other thing too that I'm going to talk about briefly is the storage engine. 11:11.680 --> 11:16.960 So the cool thing that I really like about my sequel is the fact that it has the 11:16.960 --> 11:19.840 sort of replaceable storage engines, right? 11:19.840 --> 11:25.320 For those running OLTP workloads today in 2026, I almost just said 2025 there, but we're 11:25.320 --> 11:27.200 not there anymore. 11:27.200 --> 11:29.360 You know, DB is kind of the de facto standard, right? 11:29.360 --> 11:32.880 That a lot of people are using, but there's been others in the past, there's things like 11:32.880 --> 11:39.080 Brock's DB, or MyRox for doing, you know, LSM based like high right workload kind of 11:39.080 --> 11:40.080 stuff. 11:40.080 --> 11:44.800 And this is one of the things that I think has really made my sequel a lot more broadly 11:44.800 --> 11:49.200 usable and applicable because a lot of companies can choose a storage engine that fits their 11:49.200 --> 11:50.840 needs very well, right? 11:50.840 --> 11:54.880 If you know you have a high right workload and you know, or maybe you have a mix of 11:54.880 --> 11:58.440 kinds of workloads, you can actually be running all of the same very powerful database 11:58.440 --> 12:03.720 engine like MySQL, but choose the storage engine that works right for the type of workload 12:03.720 --> 12:05.880 that you're running. 12:05.880 --> 12:11.160 So it really makes it very adaptable for scaling out different kinds of workloads, whereas 12:11.160 --> 12:15.640 in Postgres, you don't quite have the same well, like there's the I'm going to go back 12:15.640 --> 12:16.640 to this slide here. 12:16.640 --> 12:19.640 I don't have a lot of details on the slide, but the way that it works is you're storing 12:19.640 --> 12:22.920 all of your data in a heap file, which we're going to learn about a lot more in a second, 12:22.920 --> 12:26.800 and sort of the base storage engine that you get doesn't have some of the niceties and 12:26.800 --> 12:29.840 maturity of the storage engine of MySQL. 12:29.840 --> 12:34.160 So some of the things that I like and I'm excited about in Postgres is that one, there's 12:34.160 --> 12:38.240 a lot of extensions for sort of improving this, right? 12:38.240 --> 12:41.360 Postgres is known as, you know, sometimes people with high right workloads and a lot 12:41.360 --> 12:45.840 of churn on their tables, end up with a lot of table bloats, and there's extensions, like 12:45.840 --> 12:49.040 PG repack, and PG squeeze to help with these kind of things. 12:49.040 --> 12:53.440 But I'm also really excited about some new developments in Postgres storage engines like 12:53.440 --> 12:54.440 OrioleDB. 12:54.440 --> 12:57.760 Do we have anyone in the room who's working on OrioleDB or knows a good amount of what that 12:57.760 --> 12:58.760 is? 12:58.760 --> 13:01.600 I'll be curious to talk to you if you do, right here, okay? 13:01.600 --> 13:03.600 Let's chat after. 13:03.600 --> 13:06.680 But this is something that I think is really cool because it's kind of bringing some of 13:06.680 --> 13:14.240 the ideas that I really like about sort of an undo-based log, MVCC model to Postgres, 13:14.240 --> 13:17.720 and in my opinion, it's kind of a best of both world storage engine that's going to be 13:17.720 --> 13:20.360 coming in the near future. 13:20.360 --> 13:25.520 So this is, of course, it's not really about which tech wins or which tech loses, probably 13:25.520 --> 13:27.040 not the best title there. 13:27.040 --> 13:30.320 But the way that I like to think about this is like in all of these different categories, 13:30.320 --> 13:33.240 what are the strengths and weaknesses of each of these databases? 13:33.240 --> 13:37.960 And I say this because I think over the course of time as these two technologies continue 13:37.960 --> 13:41.760 to evolve, we can kind of learn from the other ecosystems, right? 13:41.760 --> 13:45.920 Things that Postgres does well, maybe can be carried over into my SQL going forward and 13:45.920 --> 13:48.520 vice versa into Postgres. 13:48.520 --> 13:52.320 And then we're going to get even deeper dives than a second here on Clustered Indexes 13:52.320 --> 13:54.720 versus the heap and replication. 13:54.720 --> 13:58.680 So I'm going to wrap up here and who might I think, Pep, you're going to go next. 13:58.680 --> 14:00.400 So I'm going to hand it over to you. 14:00.400 --> 14:21.200 Well, I'm Pep, hello, and a computer used to be somebody who made calculations. 14:21.200 --> 14:28.280 But in the second half of the past century, that concept changed first to a device that is able 14:28.280 --> 14:37.720 to do calculations, and later it moved to a device that is able to process data. 14:37.720 --> 14:46.680 And then what happened is that the cost of the unit of processing went down while the 14:46.680 --> 14:51.520 cost of storage, it went down, but not that fast. 14:51.520 --> 15:02.640 And the capacity growth, we have computing the growth was a skyrocketing while storage 15:02.640 --> 15:06.640 was growing, but not that much. 15:06.640 --> 15:14.720 What this meant was that data replaced processing in terms of value. 15:14.720 --> 15:22.880 It was the value of data was more than the value of processing. 15:22.880 --> 15:27.280 And at that time, relational databases appeared. 15:27.280 --> 15:36.600 With relational databases, three concepts appeared, like concurrent access, multiple users 15:36.600 --> 15:41.480 access the same data at the same time. 15:41.480 --> 15:49.480 We had transactions, so things changes in data were all or nothing, and we had the 15:49.480 --> 15:55.560 capability to change multiple types of data at the same time. 15:55.560 --> 15:59.200 And all these things had to be done in a consistent manner. 15:59.200 --> 16:11.360 So we needed the ability to see a constant or a permanent thing that is changing at the 16:11.360 --> 16:12.600 same time. 16:12.600 --> 16:23.200 And the only way to implement this was to have a way to have multiple versions of the data. 16:23.200 --> 16:27.080 So multiple multi-version concurrency control appeared. 16:27.080 --> 16:29.640 We have multiple versions of the data. 16:29.640 --> 16:35.040 If the transaction can fail, this means that at least we need two versions, one with the 16:35.040 --> 16:38.600 new version of the data and one with the old. 16:38.600 --> 16:44.880 But as we also need to keep consistency, we need to have not two but a lot of versions. 16:44.880 --> 16:50.640 And we don't know how many versions we will have because we don't know how long a transaction 16:50.640 --> 16:52.640 will take. 16:52.640 --> 16:58.440 And well, if we have a lot of versions of the data, we need to be able to know which 16:58.440 --> 17:04.000 is the version that I am going to read. 17:04.000 --> 17:11.040 And also, as we have a lot of versions, we need a way to be able to delete old versions 17:11.040 --> 17:14.840 once we don't need them anymore. 17:14.840 --> 17:27.200 So how is MBCC done in Postgres and in my skill, but actually in a DB, we need multiple 17:27.200 --> 17:28.200 versions. 17:28.200 --> 17:30.760 Where do we start the multiple versions? 17:30.760 --> 17:35.840 In Postgres, we store the versions on the table itself. 17:35.840 --> 17:43.200 So here we have the table and we have version 1, version 2, version 3, version 5. 17:43.200 --> 17:46.040 In DB, this is different. 17:46.040 --> 17:48.800 On the table, we just have the last version. 17:48.800 --> 17:55.280 All the other versions are stored in the undo, which is the dedicated storage. 17:55.280 --> 18:01.480 So here we have the first difference in Postgres, the versions of the row are in the 18:01.480 --> 18:13.640 heap in the DB, they are in the heap, well, in the cluster index and then in the undo. 18:13.640 --> 18:22.960 So we have multiple versions, but how we can identify which is the version we should see. 18:22.960 --> 18:30.520 We need to assign an identifier to each transaction and then use this identifier to mark the 18:30.520 --> 18:38.520 rows, and this way we will be able to know who did each of the changes and to start 18:38.520 --> 18:44.200 this information, we will start in the row itself. 18:44.200 --> 18:51.920 In DB, we have in the metadata, we have the identifier of the transaction, then we have 18:51.960 --> 18:58.560 the row pointer that points to the old version of the row, and we have some additional 18:58.560 --> 19:06.920 flux that we will use, for example, to know if our row has been actually deleted. 19:06.920 --> 19:12.480 We have some more metadata for the purpose of this presentation. 19:12.480 --> 19:19.360 We don't need this, and also the rows, it doesn't matter if they are in the cluster 19:19.360 --> 19:27.800 index or in the undo segment, we have more or less the same metadata. 19:27.800 --> 19:36.040 And the fact that we have a pointer between rows, when we find a row in the cluster 19:36.040 --> 19:43.960 index, it will point to the old versions in the undo, and in the undo will find a row 19:43.960 --> 19:58.920 that points to a previous version, and then a pointer to a previous version. 19:58.920 --> 20:23.920 Okay, okay, it's gone, hello, hello, can you give me? 20:23.920 --> 20:53.920 Okay, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, 20:53.920 --> 21:23.920 Thank you, thank you, thank you, thank you, thank you, thank you you, thank you, thank you, thank you for being safe looks, thank you, thank you you were nice, I love seeing you, thank you so much, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you, thank you thank you, thank you 21:23.920 --> 21:26.920 In order to kill has been out here. 21:41.920 --> 21:43.920 1-2-1-2. 21:44.920 --> 21:46.920 I'll just go 1-2-1-2. 21:47.920 --> 21:49.920 1-2-1-2. 21:54.920 --> 21:56.920 1-2-1-2-1-2. 21:59.920 --> 22:01.920 1-2-1-2. 22:02.920 --> 22:04.920 1-2-1-2-1-2. 22:05.920 --> 22:11.920 1-2-3-4-5-6-7-8-9-1-2-1-2-1-2. 22:16.920 --> 22:17.920 1-2. 22:19.920 --> 22:21.920 1-1-1-2-2-2. 22:22.920 --> 22:24.920 1-2-1-2. 22:26.920 --> 22:27.920 3-草 search for a map. 22:32.920 --> 22:35.920 3-1-2-1-2. 22:37.920 --> 22:40.920 1-2-3-3-1-2-3-7-3-7-4-2-2-1-2-3-3. 22:45.920 --> 22:48.920 1-2-1-2-1-1-1-1-1-1-1-2-1-1-1-1-1-1-1-1-1-1. 22:48.920 --> 22:50.560 I mean, this works, right? 22:51.240 --> 22:52.440 What? 22:53.200 --> 22:54.940 Okay, 22:58.760 --> 23:00.040 So my fatt 23:14.320 --> 23:16.040 One, two, one, two. 23:16.480 --> 23:19.480 One, two, one, two, one, two, one, two, one, two. 23:19.480 --> 23:20.120 Yeah. 23:20.140 --> 23:22.120 One-One-one-one-two-two-two-two-two-two. 23:22.120 --> 23:24.280 One-two-one-two-one-two. 23:24.280 --> 23:27.000 One-two-one-two-one-two. 23:27.000 --> 23:31.120 I mean it shirts here so they are just so beautiful here and here you can go and there. 23:31.120 --> 23:32.720 Yeah! 23:33.740 --> 23:35.760 One-one-one-one-two-two. 23:35.760 --> 23:40.760 Yeah, yeah, we can show it. 23:40.760 --> 23:42.760 Let's show it. 23:47.760 --> 23:50.760 So the situation is that it is record. 24:05.760 --> 24:07.760 You 24:35.760 --> 24:37.760 You 25:05.760 --> 25:07.760 You 25:35.760 --> 25:37.760 You 26:06.760 --> 26:07.760 You 26:30.760 --> 26:32.760 See there? Give me a sec. 26:32.760 --> 26:34.760 I have DX, no 27:02.760 --> 27:09.400 I have a license 27:09.680 --> 27:14.080 Nick, you all, Nesh, Testing the mic. 27:20.080 --> 27:23.700 This, the, check... 27:26.300 --> 27:28.940 calling info, report. 27:29.040 --> 27:31.780 Okay, This is not right. 27:32.040 --> 27:34.100 Myua, myua, stop! 27:34.880 --> 27:36.560 Check, check... 27:39.400 --> 28:09.400 As we could know, it was a new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new 28:09.400 --> 28:39.400 new and new, new, new, new, new, new, new, new, new, new, new, new, new, new, new new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, new, anE, new, new 28:39.400 --> 28:48.400 Hello, okay, my name is Pepp, and I'm sorry. 28:48.400 --> 28:56.080 As I was saying, we have a metadata in it row, so we have the session identifier, the row 28:56.080 --> 29:04.400 back pointer that points to all the versions of the row, and then we have some flags. 29:04.400 --> 29:14.400 What we have here is a chain progression, so row, version 5 points to version 4, 29:14.400 --> 29:22.400 then version 4 to 3, 3 to 2, and 2 to 1, okay. 29:22.400 --> 29:31.400 In post-grace, we have also metadata, but we have some additional fields. 29:31.400 --> 29:43.400 We have the X-Men, and this is the X-Men identifier, the transaction that created that row version, 29:43.400 --> 29:44.400 okay. 29:44.400 --> 29:51.400 Then we have the X-Max, that identifies the transaction that made that version obsolete. 29:51.400 --> 29:57.400 So if X-Max is empty, this means there are no new versions. 29:57.400 --> 30:05.400 We have the CTAD, that points to the next version, not to the previous, okay. 30:05.400 --> 30:10.400 And we have something additional called visibility bits. 30:10.400 --> 30:19.400 We will see them later, and the way progress works is that version 1 points to version 2, 30:19.400 --> 30:29.400 then version 2, version 3, and version 3 to version 4, and then version 4 to version 5. 30:29.400 --> 30:40.400 So here the differences are all versions points to new versions, while in the B, new versions point to all versions, 30:40.400 --> 30:45.400 and we have differences in the metadata we have. 30:45.400 --> 30:51.400 And also, we restore everything. 30:51.400 --> 31:03.400 If a row is rolled back, we have that row stored in the table, while in the B, 31:03.400 --> 31:07.400 we always store active or committed rows. 31:07.400 --> 31:24.400 So when we undo our transaction, we remove all the traces of that transaction. 31:25.400 --> 31:28.400 So white, so white here, okay. 31:28.400 --> 31:36.400 Well, the problem that we have, this is like that missing, I don't know why. 31:36.400 --> 31:43.400 Okay, no, it's something happened with the order of the whites. 31:43.400 --> 31:49.400 So the problem is that if we know the ideas of the transactions, that's not enough. 31:49.400 --> 31:56.400 Because we also need to know if that transaction was committed or is simply active. 31:56.400 --> 32:03.400 So if I find the row, that row may be just belonging to an active transaction, 32:03.400 --> 32:13.400 and could be a row that are committed to handle this, what we use is something called as nations. 32:13.400 --> 32:26.400 What doesn't option brings us is a way to identify if a row should be visible or not. 32:26.400 --> 32:32.400 And this option is created at the beginning of the transaction or the statement. 32:32.400 --> 32:35.400 These depends on the isolation level we are running. 32:35.400 --> 32:42.400 So if we are running, repeat our read, then this option will be created at the beginning of the transaction. 32:42.400 --> 32:51.400 If we are running in written method, then we have to create a snapshot on each statement we will run. 32:51.400 --> 33:01.400 And what we have in the transaction is a way to identify transactions in the past transactions that are active, 33:01.400 --> 33:04.400 and also transactions in the future. 33:04.400 --> 33:15.400 Because it can happen that while I am running at the transaction or the transaction to start after the beginning of the transaction. 33:15.400 --> 33:32.400 How this is done in Portuguese, in Portuguese, the snapshot, because it has the expertise that identifies, let's say, the frontier for the future, 33:32.400 --> 33:36.400 or everything after that value is in the future. 33:36.400 --> 33:44.400 We have to examine that identifies the past everything here is for sure done, 33:44.400 --> 33:49.400 and then we have a list of active transactions. 33:49.400 --> 34:01.400 And we have something very important because as in Portuguese, we have stored data of a transaction that has the transactions that have been rolled back. 34:01.400 --> 34:06.400 We need a way to know if a transaction, the outcome of a transaction. 34:06.400 --> 34:09.400 So this is in the commit work. 34:09.400 --> 34:19.400 So we have the transaction timeline, and also a way to know the outcome of a transaction. 34:19.400 --> 34:29.400 Does this mean that for every row, I need to, I find a row, but I need to know the outcome of that transaction. 34:29.400 --> 34:36.400 So this means I look at the row, and I have to go to the select, for another row, I look at the row, then I have to go to the select. 34:36.400 --> 34:42.400 There's a way to avoid this is using the way to avoid this is using the visibility dips. 34:42.400 --> 34:55.400 So when I read a row, if I go to the select, and I see that the row is visible, I update the visibility bits of that row. 34:55.400 --> 35:03.400 So this means that in Portuguese, reads can write. 35:03.400 --> 35:11.400 This page makes the page dirty, so that page will be flush, but it's not written in the wall files. 35:11.400 --> 35:19.400 So if you change the visibility bit and the data is precious, that change will be lost. 35:19.400 --> 35:29.400 But it's not important because at the end of the day, it's just something that you get by looking at this law. 35:29.400 --> 35:43.400 In anatomy, there is quite similar, but we don't have this law, because as I said before, we just get data of active and committed transaction. 35:43.400 --> 35:50.400 And the visibility bits are complex, there are a few rules here. 35:50.400 --> 35:56.400 It's just to make the math. 35:56.400 --> 36:01.400 So in postures, I also something important. 36:01.400 --> 36:06.400 Transaction IDs is that every transaction has an idea sign. 36:06.400 --> 36:09.400 Actually, this is not completely true. 36:09.400 --> 36:13.400 We assign IDs when the transaction performs a change. 36:13.400 --> 36:17.400 While we don't have a change, we don't need to assign an idea. 36:17.400 --> 36:25.400 So we create a snapshot that gives us a view of the database, but without an actual transaction ID. 36:25.400 --> 36:32.400 That transaction ID will be assigned when we perform a row. 36:32.400 --> 36:39.400 Postures uses a snapshot and select plus additional bit later, like the visibility bits. 36:39.400 --> 36:45.400 While in a DB, you just read the views, that's a name of a snapshot. 36:45.400 --> 36:52.400 And the current transaction ID, or zero, if it hasn't been generated. 36:52.400 --> 36:55.400 So thank you very much, questions. 36:55.400 --> 37:04.400 No. Sorry, I did not understand. 37:04.400 --> 37:14.400 Okay, it looks like I'm losing this light. 37:14.400 --> 37:16.400 They're blind, I don't know why. 37:16.400 --> 37:19.400 Okay, so I'll explain. 37:19.400 --> 37:21.400 So it's great. 37:21.400 --> 37:29.400 We know that the changes were done and all the stuff. 37:29.400 --> 37:35.400 And we have a lot of versions, but we need to be able to clean those versions. 37:35.400 --> 37:40.400 Because otherwise, we will run out of a space. 37:40.400 --> 37:48.400 Okay, in order to know this, we have to waste to do it. 37:48.400 --> 37:51.400 In a DB, what we have is the parts process. 37:51.400 --> 37:57.400 What the parts process does is cleaning, but how can we clean? 37:57.400 --> 38:03.400 In order to be able to clean, we assign another number to the transaction. 38:03.400 --> 38:06.400 And that number is assigned when the transaction is committed. 38:06.400 --> 38:09.400 That number is the transaction number. 38:09.400 --> 38:13.400 Okay, so when we commit a transaction, we assign that number. 38:13.400 --> 38:23.400 And we store in something called the history list, a pointer to the metadata of the transaction. 38:23.400 --> 38:27.400 And this information will be used. 38:27.400 --> 38:37.400 The information with data that we have in the review to find all the versions generated by the transaction. 38:37.400 --> 38:43.400 And to delete them if they are not needed by any other transaction. 38:43.400 --> 38:52.400 Okay, so we need to jar a little bit looking at what's running and the past of the transaction. 38:52.400 --> 38:56.400 Unfortunately, this is done using vacuum. 38:56.400 --> 39:09.400 What vacuum does is looking at the whole table to find the rows that are not visible anymore. 39:09.400 --> 39:16.400 So this would be extremely expensive because you would need to scan the heap every time. 39:16.400 --> 39:21.400 So to avoid doing this, there's something called the visibility map. 39:21.400 --> 39:28.400 The visibility map is a map, a bit map of pages with two bits. 39:28.400 --> 39:32.400 But here we will talk mostly about the first one. 39:32.400 --> 39:38.400 The first one says if that page has all the rows visible. 39:38.400 --> 39:44.400 So when I change a page, I place that bit on off. 39:44.400 --> 39:47.400 So I said, no, all the rows are not visible. 39:47.400 --> 39:51.400 And after some time, vacuum will look at the page. 39:51.400 --> 39:53.400 We'll look at all the rows. 39:53.400 --> 39:59.400 And if all the rows can be made visible, it will say all visible. 39:59.400 --> 40:04.400 And it also will clean all the versions of the row. 40:04.400 --> 40:12.400 And something that vacuum does is also freezing rows. 40:12.400 --> 40:17.400 But there is beyond the scope of this presentation. 40:17.400 --> 40:25.400 So the final difference is that postgres cleans the rows using vacuum. 40:25.400 --> 40:27.400 And the formation of the visibility map. 40:27.400 --> 40:32.400 While the visibility cleans all versions using the history list. 40:32.400 --> 40:34.400 I'm not sure. 40:42.400 --> 40:44.400 We'll try to keep schedule in time. 40:44.400 --> 40:47.400 There will not be time for it. 40:47.400 --> 40:48.400 All right. 40:48.400 --> 40:50.400 We are rolling it in Shlomi. 40:50.400 --> 40:51.400 We're with Planet Scale. 40:51.400 --> 40:53.400 We're both maintainers for VTests. 40:53.400 --> 40:54.400 It's a CNCF graduated project. 40:54.400 --> 40:56.400 A shot in front for my skill. 40:56.400 --> 40:59.400 And we're also both working on Nike, 40:59.400 --> 41:02.400 which is a shot in framework for Postgres. 41:02.400 --> 41:04.400 So we're both working on all stuff, 41:04.400 --> 41:09.400 replication, streaming, schema changes, schema tracking, etc. 41:10.400 --> 41:15.400 And today we'd like to discuss the design decisions behind logical 41:15.400 --> 41:18.400 replication for both Postgres and my skill. 41:18.400 --> 41:23.400 And how those design decisions affect you the users of logical 41:23.400 --> 41:24.400 replication. 41:24.400 --> 41:27.400 So we'll have the room here is very familiar with Postgres. 41:27.400 --> 41:29.400 Half the room is very familiar with my skill. 41:29.400 --> 41:34.400 Let's start with a very succinct and high level overview of logical 41:34.400 --> 41:35.400 replication in both. 41:35.400 --> 41:38.400 With my skill, you have a primary server. 41:38.400 --> 41:41.400 And as you write to the primary server, 41:41.400 --> 41:45.400 it generates vine riddles, which is something apart from what you may know 41:45.400 --> 41:46.400 as the transaction log. 41:46.400 --> 41:51.400 And it's essentially the change log of anything that changes within that 41:51.400 --> 41:52.400 database. 41:52.400 --> 41:54.400 So that includes not only every insert delete update, 41:54.400 --> 41:59.400 but also like any time you add a user or drop a table, etc. 41:59.400 --> 42:02.400 A replica connects to the primary. 42:02.400 --> 42:06.400 And through replication protocol asks for copies of those binary 42:06.400 --> 42:11.400 log events and stores them locally in a temporary relay log. 42:11.400 --> 42:16.400 And then when when able to processes through the relay log, 42:16.400 --> 42:20.400 reads the events and replays it, replays them. 42:20.400 --> 42:22.400 It literally replays them. 42:22.400 --> 42:26.400 When it sees a drop table, it applies that drop table. 42:26.400 --> 42:30.400 When it sees an insert, it goes ahead and inserts a row. 42:30.400 --> 42:33.400 In doing so, it generates its own binary log, 42:33.400 --> 42:38.400 and is able to then stream those changes downstream. 42:38.400 --> 42:43.400 So my skill replication is natively logical. 42:43.400 --> 42:46.400 Right? Every binary log is really every binary log event 42:46.400 --> 42:49.400 is really at change to the database. 42:49.400 --> 42:53.400 The other distinction here is that the binary log always exists. 42:53.400 --> 42:57.400 It's a pair configuration, but really it always exists. 42:57.400 --> 43:02.400 And independently of any client, any replica, how many replicas. 43:02.400 --> 43:06.400 There's the binary log, it's always there. 43:06.400 --> 43:09.400 Postgres works very differently. 43:09.400 --> 43:13.400 So the process primary writes wall entries. 43:13.400 --> 43:20.400 Those wall entries are binary snippets that represent the aftermath of the change. 43:20.400 --> 43:23.400 The replica pulls those wall changes, 43:23.400 --> 43:27.400 writes them down in the wall path, 43:27.400 --> 43:31.400 and then when able, according to a replication log, 43:31.400 --> 43:33.400 goes ahead and applies them. 43:33.400 --> 43:37.400 But differently from my skill, it does not replay them. 43:37.400 --> 43:40.400 It just uses those binary snippets, 43:40.400 --> 43:42.400 puts them in place or to speak. 43:42.400 --> 43:45.400 Right? It's not necessarily aware that, 43:45.400 --> 43:48.400 okay, this is dropping a table, this is insert in a row. 43:48.400 --> 43:52.400 This replication mechanism is really physical. 43:52.400 --> 43:54.400 This is not logical application. 43:54.400 --> 43:56.400 In order to enable logical replication, 43:56.400 --> 43:59.400 you will need to configure wall level to logical, 43:59.400 --> 44:03.400 which will supplement or decorate those wall entries 44:03.400 --> 44:06.400 with the necessary information for logical replication. 44:06.400 --> 44:11.400 Among which one important aspect is kind of coupling 44:11.400 --> 44:15.400 between the wall events and the system catalog. 44:15.400 --> 44:22.400 So, now that we have an overview of both, 44:22.400 --> 44:25.400 let's look at a few aspects in how the tool differ. 44:25.400 --> 44:30.400 So starting with the content, as we've pointed out, 44:30.400 --> 44:33.400 my skill, binary logs just include everything. 44:33.400 --> 44:36.400 When you subscribe, let's say you run a CDC, 44:36.400 --> 44:38.400 or you just interested in the change. 44:38.400 --> 44:41.400 When you subscribe to my skill changes, 44:41.400 --> 44:43.400 you connect as a replica, 44:43.400 --> 44:46.400 and you start getting all the events. 44:46.400 --> 44:47.400 Everything is there. 44:47.400 --> 44:50.400 Sometimes more than what you bargained for. 44:50.400 --> 44:54.400 Most of the time you're interested in a small aspect of those events. 44:54.400 --> 44:58.400 Whereas in Postgres, you create a logical slot. 44:58.400 --> 45:00.400 You give it a name. 45:00.400 --> 45:04.400 You are a very specific subscriber for those changes. 45:04.400 --> 45:10.400 And what you're getting is almost solely a table that it changes. 45:11.400 --> 45:14.400 Insert the leads updates and an occasional relation message 45:14.400 --> 45:18.400 that just describes to you what the table looks like 45:18.400 --> 45:22.400 that those changes apply to it. 45:22.400 --> 45:24.400 Next up is streaming. 45:24.400 --> 45:27.400 So, with my skill, you just connect, 45:27.400 --> 45:29.400 let's say, again, you want to run CDC. 45:29.400 --> 45:31.400 You just connect as a replica. 45:31.400 --> 45:34.400 You're using the standard my skill replication protocol. 45:34.400 --> 45:36.400 The magical server, the primary, 45:36.400 --> 45:39.400 it doesn't care that you're not a real my skill replica. 45:39.400 --> 45:42.400 And what it is that you're going to do with the information. 45:42.400 --> 45:44.400 Login and password, whatever, 45:44.400 --> 45:47.400 authentication, you connect using the my skill protocol. 45:47.400 --> 45:53.400 And the primary is happy to start streaming those binary logs to you. 45:53.400 --> 45:57.400 So, and with Postgres again, 45:57.400 --> 45:59.400 you need to create that slot. 45:59.400 --> 46:01.400 And then Postgres starts standing. 46:01.400 --> 46:05.400 You need to listen on the logical replication protocol 46:05.400 --> 46:08.400 to start capturing those events. 46:20.400 --> 46:22.400 So, before I go forward, 46:22.400 --> 46:25.400 I want to say one of the lens that we are looking for, 46:25.400 --> 46:28.400 looking through is witness. 46:28.400 --> 46:31.400 So, I don't think we're done great PR with witness. 46:31.400 --> 46:32.400 Not doing you can know it. 46:32.400 --> 46:34.400 But it powers all your slack messages, 46:34.400 --> 46:36.400 it powers GitHub issues, 46:36.400 --> 46:38.400 PRs, cursors, 46:38.400 --> 46:41.400 closed data, in witness. 46:41.400 --> 46:44.400 Uber has been adopting it now. 46:44.400 --> 46:47.400 So, it works at massive scale, 46:47.400 --> 46:48.400 very high availability, 46:48.400 --> 46:49.400 five seconds of downtime, 46:49.400 --> 46:50.400 causes an incident. 46:50.400 --> 46:52.400 We get woken up. 46:52.400 --> 46:56.400 So, for the Postgres protocol, 46:56.400 --> 46:58.400 the logical replication protocol is 46:58.400 --> 47:01.400 fantastic for a lot of users. 47:01.400 --> 47:07.400 So, when you want to do a CDC, 47:07.400 --> 47:09.400 like change in a capture, 47:09.400 --> 47:12.400 you typically want the existing data first 47:12.400 --> 47:14.400 and then you want to stream all the changes. 47:14.400 --> 47:17.400 So, Postgres has just a protocol that does it. 47:17.400 --> 47:18.400 You can just copy it automatically. 47:18.400 --> 47:19.400 No changes needed. 47:19.400 --> 47:24.400 Whereas when you work with my sequel, 47:24.400 --> 47:25.400 it's slightly different. 47:25.400 --> 47:29.400 You need to create your own snapshot first. 47:29.400 --> 47:33.400 You get the consistent GT idea at that point. 47:33.400 --> 47:36.400 And then you start streaming. 47:36.400 --> 47:38.400 That's why the star is here, 47:38.400 --> 47:41.400 that for us when we are building the sharing frame 47:41.400 --> 47:43.400 or some of these things become a problem, 47:43.400 --> 47:46.400 which we don't see in my sequel. 47:46.400 --> 47:48.400 So, we'll talk about that here. 47:48.400 --> 47:51.400 But when we do create a slot, 47:51.400 --> 47:52.400 are you postgres? 47:52.400 --> 47:53.400 We're creating it in the primary. 47:53.400 --> 47:54.400 We get a snapshot. 47:54.400 --> 47:59.400 And the nice thing is that you can export the snapshot. 47:59.400 --> 48:05.400 We can use it in your own transaction and do the copy from there. 48:05.400 --> 48:08.400 It's happened in the last couple of versions, 48:08.400 --> 48:12.400 but in general, you need to keep updating the slot 48:12.400 --> 48:14.400 on the primary as you read it. 48:14.400 --> 48:17.400 And that has an implication on wall retention 48:17.400 --> 48:20.400 and as well as vacuuming of old tuples 48:20.400 --> 48:21.400 that are held by the snapshot. 48:21.400 --> 48:27.400 So, badly behaved clients can cause a huge problem in postgres. 48:27.400 --> 48:35.400 So, same, this is related to the issue of how it connects. 48:35.400 --> 48:38.400 So, the client's can switch to the primary and replica 48:38.400 --> 48:40.400 that is no difference. 48:40.400 --> 48:42.400 And as long as you can, the bin logs are available. 48:42.400 --> 48:46.400 Whereas in postgres, since we have 48:46.400 --> 48:48.400 20, you can actually stream from a replica. 48:48.400 --> 48:50.400 Your concept of failure was lots of great. 48:50.400 --> 48:52.400 But you still need to update the primary. 48:52.400 --> 48:55.400 So, to make sure that the wall, 48:55.400 --> 48:57.400 you tell the primary that I've read up to this point 48:57.400 --> 48:58.400 and can free up the wall. 48:58.400 --> 49:01.400 So, there is a tighter coupling with the physical replication, 49:01.400 --> 49:04.400 which affects your data. 49:04.400 --> 49:11.400 And this is a more technical detail where 49:12.400 --> 49:16.400 the mechanism of slot synchronization 49:16.400 --> 49:19.400 between the primary and the standby. 49:19.400 --> 49:21.400 Are a synchronous. 49:21.400 --> 49:25.400 And that for us causes a lot of h cases 49:25.400 --> 49:27.400 when we are dealing with, you know, 49:27.400 --> 49:29.400 we want to deal with replica coming up 49:29.400 --> 49:31.400 and primary going down within seconds. 49:31.400 --> 49:34.400 Which normally is not a problem for most people. 49:34.400 --> 49:36.400 But when we are dealing with the level of scale, 49:36.400 --> 49:38.400 we are talking about this becomes a issue. 49:39.400 --> 49:43.400 The retention is entirely decided by the server 49:43.400 --> 49:44.400 in case of my cycle. 49:44.400 --> 49:46.400 It can just boys the bin logs. 49:46.400 --> 49:48.400 Of course, if the client needs that bin log, 49:48.400 --> 49:50.400 we have to start from scratch. 49:50.400 --> 49:54.400 But on postgres, because the coupling wall 49:54.400 --> 49:59.400 can get retained a lot, there is a break glass of functionality. 49:59.400 --> 50:01.400 So, it is good at least. 50:01.400 --> 50:04.400 Make sure that your postgres does not crash 50:04.400 --> 50:06.400 because of lack of this space. 50:06.400 --> 50:10.400 But there is a shorter period where 50:10.400 --> 50:12.400 a slot needs to respond. 50:12.400 --> 50:16.400 And the slot needs to keep updating everything. 50:16.400 --> 50:20.400 So, in terms of failovers, as well. 50:20.400 --> 50:22.400 So, the same, again, the same design 50:22.400 --> 50:24.400 also helps postgres with failovers. 50:24.400 --> 50:26.400 You can always failover if you are 50:26.400 --> 50:27.400 streaming from primary. 50:27.400 --> 50:29.400 You can continue from the new replica. 50:29.400 --> 50:32.400 Much more easily than it is possible. 50:33.400 --> 50:36.400 PV17, which just came out end of 244. 50:36.400 --> 50:39.400 If you the primary went down, you have to restart. 50:39.400 --> 50:41.400 So, now with failovers logs, 50:41.400 --> 50:45.400 it is much better for most users. 50:45.400 --> 50:49.400 At our scale, we have a little bit of edge case issues 50:49.400 --> 50:53.400 where we care for about orchestration there. 50:53.400 --> 50:57.400 So, summary, I think logical application 50:57.400 --> 50:59.400 was native for my cycle. 51:00.400 --> 51:02.400 Much longer, so it is a lot more stable. 51:02.400 --> 51:05.400 In the fact that the client state is the client, 51:05.400 --> 51:08.400 it is not effector server as much. 51:08.400 --> 51:10.400 It makes a big difference. 51:10.400 --> 51:12.400 logical application is fairly new. 51:12.400 --> 51:15.400 It is a failover support slot of a company. 51:15.400 --> 51:17.400 But, on the other hand, a very vibrant 51:17.400 --> 51:19.400 community working, logical application 51:19.400 --> 51:22.400 getting a lot of attention in the last few sessions. 51:22.400 --> 51:26.400 And, last few are uses already sequences, 51:26.400 --> 51:27.400 which is not replicated. 51:27.400 --> 51:30.400 It is going to come in 19. 51:30.400 --> 51:33.400 We have told maybe the ideal application might come sooner. 51:33.400 --> 51:35.400 So, in that sense, it is improving. 51:35.400 --> 51:38.400 But, so, I hope, at given, 51:38.400 --> 51:40.400 we all given, 51:40.400 --> 51:44.400 flavor of what the differences are. 51:44.400 --> 51:47.400 With respect to logical application. 51:47.400 --> 51:49.400 Thank you very much. 51:57.400 --> 52:01.400 Thank you very much.