We're now picking up where we left off before spring break, before the midterm of burning out the actual system further. So again, the overview of where we're at in the semester is that we talked about the networking layer, and then we're starting from the bottom and sort of going up, although we've already covered the storage manager. So right now we're at this part here, where the query plans are going to show up through the networking layer. We'll talk about how SQL shows up through the networking layer. We'll talk about how the optimizer and the planner is going to generate a query plan, and now we're talking about, if we assuming we already have a query plan, now we need to start executing the operators in that query plan to produce results for our query. So we're at this point here, but then now we're still going to go up the stack and talk about how we can then compile plans into sort of efficient machine code to execute them very efficiently. That's what the team was talking about with the DSL stuff from last time. Then we'll go up even further again and talk about how we actually generate an efficient query plan in our optimizer. So again, we're here, we're going up. So the next couple of lectures are really going to be focusing on operator execution, how can we take again some component or operator in our query plan and execute them efficiently. This is now going to be going way deeper than we've ever really covered in the introduction class. Because now we're going to actually start really caring about what's the hard work they're going to do, where's the data we want to operate in memory, what's in our CPU caches, what are some additional instructions that the CPU provide us that can also do things in parallel or more efficiently. So basically, we're going to have a big bag of tricks we can do to run these queries super fast. Query plan processing, what we're talking about today is basically how we're going to organize the overall system to have it execute the operators in the query plan. But we're not going to talk about what actually those operators are just yet. That's when we started getting into like inlining application logic for user defined functions. That'll be next Monday. The parallel join algorithms vectorized operations, or vectorized operators using SIMB and then query compilations. So again, all of these together are the things we're going to use to execute operators. The high-level thing we're talking about today is how we organize the system to execute these operators. Where do they send their data? Then everything else will then be, now within a single operator, what does some crazy sh**ing do to make that run really fast? Some of these things are easier to do because we're in memory. We're not worrying about disk. So again, the goal of what we're talking about today and going forward is, we have some query plan that the optimizer generated from SQL doesn't have to be SQL, but in our world it is. Then inside of this query plan, we're going to have operators. We'll make a distinction between physical operators and logical operators later on. But for our purposes, we have a physical operator that says, I want to do X on some data that I'm getting from either a table, an index, a child operator, it doesn't matter. Then it's going to come to that, produce some output. Then we'll say an instance of that operator. Since we want to be able to run this in parallel, we'll call this an operator instance. So one core could take one operator and deploy it on multiple cores and all of them are running in parallel. Each of those would be an instance. Then a task or pipeline will be a sequence of one of these operator instances running within a single core. So our purposes here, we're focusing on at a high level, how are we taking these guys, the tasks or the pipelines and having them run on different cores? Where are they getting the data from and where do they send their data to? That's the goal of today, but we need to understand why we want to organize things a certain way. As I already said, if you get rid of the disk, which is the whole point of this semester, if we get rid of the disk, everything fits in main memory, then the goal for how we're going to speed up queries isn't as obvious as it was before. In a disk-based system, the disk is always the slowest thing. Network also sucks too, but sometimes you can't avoid that. The disk sucks, it's slow. So we want to do things like heavyweight compression to minimize the amount of IO we're doing, or minimize the time it takes to get data into memory. But now disk is gone, we still need it for logging and that's unavoidable. But now the thing we want to target to speed up our system, it's not as obvious as it was before. So it's going to be the orchestration of a bunch of different ideas together to speed things up. Now query compilation is going to be a huge win, vectorization also matters, parallelization also matters. So what I'm trying to say, there's not one thing I can point to you say, if you're building new data from scratch, do this, do this one thing first. We are actually trying to do all of them, because in some ways if you're building a modern system, you want all of them, but there's no one of these that are going to stand out clearly better than others. So what are our goals now? If we assume everything's in memory, the disk is not along the bottleneck, what kind of things we need to start caring about? Well, it's the low level parts of what the actual CPU is going to do. So there's three different optimization goals we could have in trying to speed things up. The first is that we can reduce the instruction count of the execution of the query. So that means essentially we want to do less things, we're going to execute less instructions, but still produce the same amount of work, the same amount of results. And this is not something like, the compiler can help us in some ways, but many times it's also going to be us specializing our code or organizing in such a way that we reduce the amount of work we have to do in order to execute a query, or execute one of these operators. The next is going to be to reduce the number of cycles we have per instruction. So again, the high-level basic idea is here, we're going to have some number of instructions, but instead of having, taking longer to execute those instructions, assuming that they're fixed, right? We've already done maybe the first one, try to reduce the number of instructions. For now, the instructions that we have, we want to reduce the time it takes to execute them. And the metric we're going to use is to reduce the number of cycles we have per instruction. And so what does this mean? What's the main bottleneck whether it calls an instruction to take multiple cycles? Yes? Memory stores and loads? Memory stores and loads, or cache measures is another way to think about this, right? So this is us now trying to figure out to, I guess it's already said there, right? It's still a good answer. This is us trying to maximize the locality of data that we have in our caches and we reuse it as much as possible. And we'll see when we talk about the processing models, like the volcano processing model, or the iterator processing model, these techniques are written in such a way that they're actually bad for locality. Because maybe you go operate on one tuple and then rather than riding along that tuple and doing as many things as possible with it, you go back and look at the next tuple, right? The last one will be to obviously paralyze execution, right? We don't need to say this, Morse law is ending, so we're not gonna have way faster clock speeds. The sort of hitting the physical limit of how small the die size can actually be, whether the transistor size can be. So we're not gonna get a huge performance just because the CPU got better for a single core.  We're gonna make sure that now we implement operators and we can execute these in parallel efficiently. So we'll talk a little bit about today how we organize the overall query plan when we execute it to paralyze operations. But then when we talk about in the next couple of weeks, we can take like a single join algorithm and how many run that efficiently in parallel, okay? All right, so today our agenda is sort of three parts. We're gonna begin with the vector-wise paper or the MoNAB X100 paper that you guys read and talk about their analysis of what modern CPUs look like and why existing implementations of database systems at the time in the mid-2000s while they were inefficient for the architecture that still looks a lot, not exactly the same as they described in the paper, but some parts of it still are the same. Then from this, we then talk about, again, the processing models of how we actually want to take a query plan, break up its operators into tasks or pipelines, and then have them be scheduled within our system, using all the scheduling stuff we talked about before the break. And then we'll finish up talking about at a high level what different variants of parallel execution look like. And again, think a high level for the entire query plan and then we'll talk about in the subsequent lectures how we can execute each operator in parallel, okay? All right, so the paper head you guys read, as I said, it's from 2005, so it's almost 15 years old. But to me, I actually love this paper. One, because it's super easy to read and the stuff at the end with the, when they describe their system, maybe not so much, but at that beginning part, they really lay out like here's the problems you have with in-memory databases running on modern hardware and here's why everyone's gonna get crappy performance for analytic queries. So I'll say also too, like we're focusing on analytical queries here because this is where we're reading a large amount of data. For the OTP stuff, there are things you wanna do to get better performance and target it towards the hardware that you have, but the bang for the buck you're gonna get is not gonna be at the same scale as you get for analytical queries because these things are just reading way more data. There's a bunch of other overhead that you can avoid like lock contention at the illogical level that will slow down performance of a system whereas these guys don't have to sort of deal with these things because again, it's just reading data as fast as possible and processing them. So the first half of this paper provides a really good low level analysis of the performance issues in in-memory databases or actually just for all databases because they looked at MySQL as well and Oracle. But it looked at how these guys were not designed for the modern sort of CPU landscape as it existed at the time. And the way to sort of the reason about is the systems they looked at were written in a way that was sort of natural for humans to write. It was written away from an engineering standpoint that was easy for the programmer to reason about. But the way that actually is best for humans actually turns out to be the worst thing for the CPU itself. After running to get efficient execution on the CPU. So then based on these findings, they then proposed a new system at the time it was called Mone ADB X100 because Peter Bontz and Marcin came out of the Mone ADB project at CWI but then they forked this off and that then later became VectorWise. VectorWise is actually really good. We benchmarked it today. I think you've done this, right? Or no, you didn't. We benchmarked in other experiments VectorWise against some other systems we've talked about so far. And again like the last public version of this from like 2015, 2014-ish still beats modern systems. It was really good. So then VectorWise got bought by Actian. Actian is a, I don't say holding company but it's like a, they buy old databases. So they bought Ingress, they bought some other stuff but they bought VectorWise. And then they killed it. Well they renamed it to Vector. Then they killed it. Like if you didn't know what you were looking for when you went to the Actian website you wouldn't find it. And so every year I would say yeah, VectorWise is really good but like too bad Actian killed it off, right? Or they changed the name and they made it a version for Hadoop or some b***h like that, right? And so I kept saying in all of my videos like I love VectorWise too bad they killed it. Got to the point where actually somebody Actian saw it and they emailed me and they're like hey, just so you know Vector is no longer in hiding it's now back on the Actian website. Cause again if you went to the Actian website it wouldn't be available for download. But you had to know where the old link was to find it using like archive.org. Anyway, he just tells me that like this is all changed VectorWise is back from the dead. So that was kind of nice but then they actually had an announcement what is this, three or four days ago. Actian has now been rebranded as Actian Avalanche and now they're selling it as a like a data warehouse in the cloud, right? Sort of like Redshift or Snowflake or something like that, right? I can't comment to how good this is but I'll say again for the single node version that VectorWise is actually really good. Now if I remember correctly VectorWise is actually based on M-Map. Now much as I complained about M-Map again for read-only workloads M-Map is okay so they weren't doing transactions. They just load the entire database into memory. To get other backgrounds, so Peter Bantz and Marcin Zorakowski were the two people working on VectorWise. Peter went back to CWI and he's building a new system there after he left Actian. Marcin went off to go found Snowflake. So a lot of the techniques that were the things we'll talk about from the VectorWise paper and things we'll talk about going forward the rest of the semester these are the kind of things that he went off and built in Snowflake. That's part of the reason why Snowflake's really good. So it's sort of like I guess the database community is very incestuous. Okay, so there's some parts of this paper as I said that are a bit dated. Like they talk about itaniums and I fancy that some of you actually have never heard of an itanium before. Who's ever never heard of itanium? Raise your hands, okay. Oh, everyone, all right, perfect, all right.  But they talk about some things like the pipeline for the Pentium-4 chip they were looking at had like 31 stages. Whereas like a modern Oswell-Brogwell since like 2015 or so is now we're down to like 14 stages. So we don't really have that super long pipeline anymore but there are still, the problems you still have with the pipeline still are in effect and still matter to us in our database system. So again, the harbor is slightly different but the main ideas still matter to us. All right, so we need to understand what our CPU is gonna look like in order to understand how we can design the system to operate efficiently on it. So this is like everything you need to know about CPUs for databases one on one, right, in like two slides. So again, the CPUs we organize in these pipeline stages and the idea of these pipelines is that because a single instruction may take multiple clock cycles like for example, if I have to go do a load into memory it's gonna take a couple of cycles for that to end up in my CPU caches. So the idea here is that they can have the CPU operate on multiple instructions at the same time because they can have different parts of the CPU new executing something different at every single instruction. And underneath the covers again like you don't write your program assuming that they're gonna do all these weird out order stuff you know the compiler just generates the instructions and the CPU then figures out how to then sort of shuffle things around while it's running to have the thing that CPU always crunching instructions at all times, right. So these are also called to, you know to modern CPUs have these pipelines but then if you have a single pipeline if you have multiple pipelines it's called super scalar and the basic idea here is just like you do and you have multiple pipelines that are all sort of executing parallel and then keep sort of firing off these instructions if you know that they're gonna be independent of each other, right. But soon as you have like things like dependencies or branch mispredictions we'll talk about the next slide then you sort of have the CPU has to correct itself to make sure that it actually does what does things in the proper order, right. Cause you don't wanna have out of order execution of things cause that would break up above the correctness of your application for example, right. So we want to have Flynn's taxonomy so much so make more sense when we talk about parallel execution or SIMD but Flynn's taxonomy is a way to describe different computer systems. So you can have like a parallel system can be classified as what the instruction stream is or what the data stream is. So a single pipeline for this in our world is a single instruction stream, single data stream. So we have one instruction stream coming on one data stream that they're operating on and then we can sort of do that in parallel in our different pipelines. So what do we care about for super scalar CPUs? What do we care about in data systems? Well at a high level again, this is sort of what every application would care about but this matters a lot in our world and because we're the ones actually building a database system we can architect it sort of in a way to try to avoid some of these problems. So the first of that we have to deal with dependencies and this is where if you have one instruction depends on another instruction then you can't have them be in the same pipeline and sort of execute them immediately after the other cause you need the output of the first one before you can get the second one and then you need to put the output somewhere and then provide it to the second one, right? So we have to avoid, actually this is harder you can't really avoid these dependencies but the CPU is not gonna be able to get full speed execution of your instructions if you have dependencies. The one that we can program around better is do handle branches. So because to fill the pipeline is expensive and so again we have a 14 stage pipeline so we have 14 instructions and so I'm executing some instruction here and then the output of that instruction say like it's an if branch that then determines what co-path I go down. So for my remaining instructions in the pipeline I can't, I don't actually know what path I'm gonna go down so I can't fill in the instructions that are gonna execute next. So modern CPUs will try to predict what path they're gonna go down and then fill in your pipeline instructions that you would execute if you went down a particular branch. And again how they actually figure this out is like trade secret but you can think of something like keeping really track of like I've been down this path before what probability will I go down, I've seen this if branch before what probability will I go down one branch versus the other. At a high level that's essentially what they're doing but it's more complicated than that. And so what'll happen is if the branch prediction gets it wrong. So then I have to basically flush my pipeline throw away any maybe speculative work I've executed assuming I was gonna go down a particular branch I throw all that away then load in the branch I should have gone down into my pipeline and then start executing that.  We can't do that. That's all underneath the covers to us. So where is the most obvious thing in a database system where this thing becomes problematic? Well what's the most common thing we're gonna execute in our database system where we would have branches? Wear clause, filters, exactly, yes. So think of those. What is a wear clause? I'm scanning the table, I have some like wear something greater than something or something less than something. So I'm taking a value that comes from the tuple itself. It comes from the table and I'm comparing it against another constant. So for every single tuple I'm looking at that value from the tuple is going to change. And again unless I do some like crazy pre-sorting then it's unlikely that the branch predictor is gonna get this correct. It's gonna be completely random. So it's gonna, 50% of the time it's gonna choose the wrong path and we're gonna get bad performance. So let's look at this a little more detail and see how we actually can design a scan operator with a wear clause to avoid branches. And this is something again where we can design our database systems internals in such a way to be aware of what the harbor is actually doing and potentially get better performance because of that. So say we wanted to run a simple query like this. Select start from table, wear key greater than some low value and key less than equal to then some high value. So if you were like building a database from the first time you would implement it sort of like this. This is the branching implementation. Again I apologize for showing code in some of these lectures you just sort of have to but normally I tell my students don't show code because nobody ever meets it but this is simple enough that you should be able to follow it. For every single tuple at my table I go grab the key I wanna compare in my tuple then I'm gonna do my if branch. If key greater than equal to low value and key less than equal to the high value then I'm gonna copy it into my output buffer. And say the output buffer is just a giant array and then so I increment the offset and then I'm running to my buffer every time I add something.  We're like it's gonna depend on the data and it's just gonna be completely random distribution. So to implement this without any branches you would do this. So for every single tuple immediately copy it to my output buffer. I don't check I just copy it, right? Then when I wanna do my comparison of the key to see whether I should include it I'm just doing arithmetic operators here to tell me whether the if this is less than this then I have a one and this is sorry if this is greater than equal to this I have a one and then key is less than equal to that then I have a one. I add these two values together and that's either gonna give me zero or one. It's zero if only one or neither of these matched. It's one if only if both of them matched. Then I get that that's just my off that's sort of the value of this either one or zero is what I'm going to add to my offset in my output array. So if I don't match this goes to zero I come back around and I just overwrite the last tuple I put in there. Of course now I'm missing an extra piece here we have to check to see what was the last thing I add was the last thing I just added should be there or not if yes keep it if no then truncate the last one right there's an extra step you have to do afterwards but in this case here I'm assuming I'm gonna match I always copy it in and then I check later yes. Is the Turner operator there not counter branching? His question is the Turner operator not counter branching so that's this thing here the question mark no because you can rewrite this as math arithmetic and then it's single instruction to the comparison. Oh the compiler just does that for you? Yeah. Okay. Yes. You both have to be careful to use logical and not short circuiting and right. The statement is you have to be careful to use logical and and not short circuiting and yeah so what well wouldn't that implicitly create a branch? Yeah but like yeah so in this case here if match actually because it's not an if clause because it turns into arithmetic instructions it'll always execute both of them as far as I know yeah. Right. Don't install windows. Sorry. So again the key thing is here because here it's an if clause it's gonna you know say you do the stupidest thing you say all right the last time I went through this branch I went the last time I had this if clause I jumped into this branch here so let me go pre-execute that or refetch that in because that's what I think is gonna happen but again if it's every other one matches and every you know every odd one matches every even one doesn't match then that's the worst-case scenario because I'm gonna blow out my you know I'm mispredicting all the time. In this case here I'm paying I'm doing extra work because I'm copying things that I don't actually need but I don't have any branch misprediction so I'm just like blasting through my pipeline as fast as the clock speed of the CPU right. So this obviously depends on what the data looks like. So this is from another paper later on from the vector-wise guys where they're doing a sequential scan and they basically have the same branching versus non-branching branching versus branchless selection operator I just showed in the last slide and they're varying along the x-axis the selectivity of the where clause. So this is where you would have 0% of tuples match and this is when you have 100% of tuples match. So the red line is the no branching one and as expected no matter what the distribution of the data looks like of a selectivity of your where clause you're always doing the same amount of work and that's why it's basically a horizontal line but the arc you see for the blue line that's the branching case, right. So when everything is sort of less than roughly around 5% here. So when you have less than 5% selectivity the CPU's pre-fetching or branch predictor gets it pretty, is correct most of the time and therefore it's the benefit you get from predicting that your thing is not gonna match and not having to do branch prediction is outweighs that overhead of the extra work you're doing in the branchless case. But when you're up here and obviously when you're at 50% that's the peak because that's roughly you're wrong 50% of the time and that sucks for the CPU. So again, this is a really good example we'll see this later on this actually the branchless code actually has some other benefits when we start doing SIMD and vectorized instructions because SIMD doesn't have if clauses where a branchless approach seems like it'd be wasteful because you're doing useless work but that actually turns out to be the better approach. Okay? All right, so for the other optimization we can have by is reducing our instruction count the way to sort of think about this is that in the examples that they showed I think for MySQL on the paper was that the where clauses are super expensive because of the system is being written in such a way to be general purpose and be able to handle all of these different data types within the same code path of doing the various operators in the system. So the way to think about that is like say I wanted to do an addition I'm gonna have this giant switch operator that says if my left operand is this data type and my right operand is this data type here's the addition instruction that I wanna do. And again, that they talk a little about how vectorized handles that they do by pre-compiling those comparisons and this figuring out on the fly as you run which comparison function that you've pre-compiled you wanna run. That's one way to do query compilation we'll see the DSL or LLVM stuff later on on the fly but that's one example of how to actually avoid this problem. So again, these giant switching it sucks because that's just more if instructions and now that means more branch misprediction in the CPU and somebody's also the function calls and now it jumps into memory and that set up your stack and do this calls as well. So we already saw why this is problematic before when we talked about the numeric data type when I showed you the sample code from Postgres. But so here's our switch statement and then you see here's all these different instructions to basically do something equal something or something greater than something. In this case here we're doing fixed width or fixed decimal arithmetic but in a lot of cases for other parts of the system in the MySQL example they talked about you're gonna see these giant switch statements to handle comparisons between different data types as well because you have to cast things. So the goal for reducing the instructions we have to execute will be by kind of specializing this code to only support the data type that we actually know about ahead of time. So we're not gonna talk about how to do this just yet this will come up when we talk about compilation mostly but again, this is something in the background mind we should be thinking about how to specialize the system to get better performance because that's gonna actually be the best thing for the CPU as well. Okay, so now we wanna talk about in the processing model which I'll define as the high level approach of how the system is gonna execute a query plan and for these different processing models they're gonna have different trade-offs for different types of workloads. So we're actually gonna talk a little about OTP versus OLAP here whereas the, I mean everything I've said matters in both worlds reducing instruction count that's clearly always gonna be a good idea as I said but we're mostly describing the context of OLAP environments. For this point here we'll actually talk about both workloads. So the first approach is called the iterator model also sometimes called the volcano model or the pipeline model. Volcano was an influential system at a late 1980s, early 1990s out of, I think he was in Oregon but this guy, volcano was a sort of optimization framework. We're also gonna talk about Cascades which is the successor of volcano but this is from the same guy who wrote the locking paper you guys read about from B-Tree indexes, Gertz graphing, so he's done a bunch of stuff. So the textbook definition or the sort of more formal name of what we're describing here is the iterator model but people often refer to it as the volcano model because this paper sort of laid out how to do this in parallel first. So the idea here of the iterator model is that every query plan operator is gonna have this next function and what'll happen is a parent node will call next to its one of its child nodes to have it go send up to it or retrieve the next tuple that it's supposed to process. So for every single next function invocation you get back one tuple, right? And the idea here is that the parent node is basically gonna loop over this next function and keeps calling next, next, next on its child gets back some tuple and maybe does some iterator process before sending it to its parent and it keeps doing this calling next on its child until the child comes back and says, I don't have any more. Right, and then at that point we've processed all the data we need to process at that side of the tree in our query plan. So let's look at an example here. So say we're doing a simple join on A and B or A dot ID equals B dot ID value and then we have a simple predicate on B value. And then we have a projection at the top. So the way to think about this, and again I apologize for showing code but we have to do this, is that we have these, each of these different operators in our query plan, these correspond to a little function, a little snippet of code. And then we're gonna start at the top and we're gonna have this for loop over for every tuple in child dot next. And then every time we call child dot next that invokes this function here. I have to say down here below, like for its child give me the, give me the next tuple that you have. All right, so this one here, we're doing a loop over child dot next. We call it next down here, we get down here. And this guy's gonna loop over the left child because it's doing a join. So it calls left dot next and that lands us down here. And this is our access method or scan operator where we're actually just doing a sequential scan over A and we see we have this emit function. So this is gonna look at every single tuple in A and then for every tuple that it gets, it calls emit which then sends back a single tuple after this guy. So for every time we call emit, the execution stops here. We still maintain state, almost like an iterator in Python where we know that if we come back and book this thing again, we don't start from the beginning. We pick up where we left off but then we send this call as emit and the execution context of our thread that's running this query plan goes back up to the parent. The parent just keeps doing this, doing this and getting back single tuples until the child here says I have enough. But inside our for loop for every single tuple we get, we're gonna put it into our hash table because assuming we're doing a hash join.   So we'll talk about pipelines, we'll talk about query compilation a bit more but one way to think about this is like the left side and this thing here is a pipeline because this could run in, for every tuple I'd get I could then build my hash table but the pipeline ends after two because I can't actually get the output for my projection until I build my hash table and then I start probing it here. So like this, the top one can't proceed until the bottom children have, or at least this side here, the left side of here has produced all its results. So again, this is called pipelining and then there's a pipeline breaker that says when you can't keep going and you have to go back and get the next job. So this iterator model is used in almost every single data system that you know about, that you've ever heard of. I'm showing a small sampling here. These are the ones that actually can confirm from either looking at the source code or looking at the documentation that I know they're doing to iterate a model. Again, any transactional system, any OTP system will be doing this because this one or two exceptions that I'll show next slide, but this is just the way everyone implements it because it's the easiest one to write because you have these nice functions, abstraction you call next and get data going up. So one nice thing about this is that output control is super easy to implement this like a limit clause because you just stop calling next when you get all the data you want. You don't have to have any additional logic to have some children stop emitting results because they're gonna send up everything you need and it's almost like an on-demand request. Give me the next tuple. So if I have everything I need based on my limit clause, then I can just stop, all right? And then the pipeline breakers are these guys here. Join some queries and order buys. This is where you can't continue up the query plan with a tuple until you get all the results from one of your children, all right? So again, this is really good for OTP because, well, it's not great for OTP, but this is the most general purpose one. This is what sort of like, you can do this for analytics, you can do this for OTP. It's not particularly good at either one. It's just, again, it's a general purpose thing. The next approach is called the materialization model and the idea is that instead of when you call next, instead of getting back a single tuple, you give back all the tuples from your children. So there's one function called down below and it spits back everything that it would ever, everything that it's ever gonna generate all at once, all right? So the reason why this is good for OTP systems is because these things don't produce a lot of tuples.   But here's a good example where like because it's a bottom up approach versus potentially versus a top down approach, you do have to pass down hints to avoid scanning more data than you actually need. Like if up above I know I have a limit clause where I only care about one tuple, then down below I need to make sure it knows that I only need one tuple because otherwise it's gonna dump all the tuples up and then I throw them all away so I get the very top. So as I'm describing it, we're describing this as tuples and it sort of implies that it's a row store where you're getting all the attributes for a single tuple, but it doesn't have to be that way. It could just be like our column store approach where it's all the tuples for a single column or all the attributes within a column for all the tuples. And you just pass back that column instead of having to materialize the whole thing. So here's roughly what it looks like if this works anymore. Nope, awesome. Sorry, is it frozen?  That's weird. All right, whatever, sorry, it froze. All right, so instead of having next, we now have an output function. So at the very top, we're starting from the top going down, I call output and this says give me all the tuples that my child has so I go down here and this has output. So it goes to the left side, give me all the tuples that you have. So down here, we create a buffer, we iterate over every single tuple in A, that's the table we're scanning, we add it to our buffer and then we return it. We just send that data back up and again it's all the tuples that this operator down here is ever gonna touch or ever ever look at. So at this point here, when we call return, we never go back to this guy because it materialized all the data that it's actually gonna need. Same thing, we come down the other side, it gets its child output, it gets down here, materialized the total tuple and then send that back up and we go all the way up there. So again, I'm showing you this as a top down approach. It could also be bottom up, I could just take this thing, execute this first, produce a bunch of tuples, put it in, all the tuples that I'm ever gonna generate, put it in some buffer and then had this guy then read from that buffer. But in this case here, I'm going top down because it looks like the other one. So this, I think my opinion, the bottom up approach with materialization model is the right way to do the OOTP because it's fewer function calls, it's fewer coordination between these different operators. We don't care about parallel execution in OOTP for a single query which is called intro query parallelism because there's, if I'm gonna go read one tuple, I can't really parallelize that, right? So this bottom up materialization model is the best approach, I think the most lightweight approach for OOTP. For OLAP, I think it's a bad idea and this is actually what Monadibi did and this is what the vector-wise guys said, no, this is wrong, this is the right way to do this and which is they're in the vectorized model. But Monadibi did this, at least the old version of Highrise did this which was an HTAP system with roots from some ways from the Monadibi project. But these guys do this, now they were column stores so they were materializing the entire column and sending it up but again, if I have a billion tuples, my select operator filters out maybe half of them so I have a half a billion tuples. I have to make a buffer of a half a billion tuples and shove it from one operator to the next as you have these really large intermediate results which may not be good for Casual County, may put a lot of memory pressure on the system and your caches. So again, this is why I think this is a bad idea and no system with exception from Monadibi really does this. All right, so the last model is again what the vectorized came up with and again, it sort of seems obvious now but at the time this was novel, this was new. So it's gonna look a lot like the iterator model where we're gonna have a next function that the parent calls on the child but instead of getting back one tuple you're actually gonna get back a batch of tuples or a vector tuples. Now the size of this vector can depend on what the hardware actually looks like. We'll talk about this later on with vectorized execution but it's some subset of the total data that an operator is gonna generate and it's size enough that it'll fit in CPU caches. And so they're sending the data from one operator to the next is a really cheap operation. So what this is gonna allow you to do now in our internal loop inside of our operator before I was showing you these functions where it was like, get for one tuple, do something. When we start talking about vectorized execution now if we iterating over our batch of tuples now we can use SIMD, basically vectorized instructions to take a bunch of data, feed that into the CPU for one instruction and then that produces a bunch of answers in parallel all at once with one instruction or a small number of cycles. Again, this will make more sense when we talk about the vectorized execution stuff with SIMD but that's, if you do this then it makes, you can do the vectorized execution stuff later or the vectorized operated execution later. So going back to our example, right? So now inside of our little code snippets for operators we generate the output buffer like the materialized model. I guess that should be next, sorry, not output but it doesn't matter, right? But now what we're doing is we're iterating over our data from our children and they're gonna generate a buffer and when the buffer reaches a certain size we emit it as output. So again, same thing, going top down we just keep calling output or next and these guys keep shoving data up, right? So like to think about this, like so here this probe on a single tuple, this could be a vector of tuples to do the probe in parallel inside of our hash table, right? Using, so we're getting sort of like, we're getting sort of the intracranial parallelism across different operator instances running at the same time but then each single operator instance we can then run instructions in parallel using SIMD which will be a big, big win. So in my opinion, this is the way to build a modern OLAP system today and there's a bunch of the newer systems and now also put this. So like DB2, Oracle and SQL Clever like the base system is a row store that doesn't do this but if you buy their query accelerators or their comm store engines, they will do what I'm describing here. So that's why I'm including them there but vector-wise is again, what the MonoDB X100 thing that you guys read are now vector or Avalanche, this is where this all came out of and Snowflake was founded by an X vector-wise developer, right, so that's a lot of the ideas that came out of vector-wise they put into Snowflake. All right, so I've already sort of alluded to this but just to say it concretely, again in all my examples I was showing you what's called a top-to-bottom or top-down approach for query processing where we have a query plan and the first thing we do is go grab the root of the query plan tree and we fire that function or fire that snippet and it calls next on its children. So the execution permeates from the top, goes down and then essentially pulls data up to the operators as needed. But I did talk about the bottom-to-up or the bottom-up approach in the materialized model. This is where we start the bottom of basically our scan operators on our tables or indexes, it doesn't matter and they start iterating over their data source and then they shove data up into their parents, right? Again, at a high level it sort of seems like it's the same thing and semantically yes, like it actually used to query, like it doesn't matter whether it comes in the top-down or the bottom-up. But the bottom-up approach turns out to be better because you're gonna have tighter control of your caches and registers in your pipelines. So you're gonna have tighter control of how you move data up into the tree. And then now for your pipelines, now you can do things like well I can keep this CPU or keep this tuple with its values in not just cache with CPU registers and pass that along from one operator to the next and that because CPU registers are the fastest memory you can have, faster than L1, L2, L3. If I keep things in my registers then I can have full control over that then I can get even better performance. So this idea of pushing from the bottom-up and doing co-gen, a lot of these ideas came in hyper. You will read the paper that describes how to do this and this is actually what we did in our own system in the old version of Peloton and what we're doing now in the new system today. So for all of that, I think the vectorized approach plus bottom-up is the right way to go and you'll see this out of the hyper-paver, yes. So why can't you pass data off with that in the approach one?  This is like, I'm basically unrolling the operators like there's snippets, I'm thinking like unrolling the loops and like executing as many things as I can within one pass in a loop.  And it can be some sort of call you say register. So his statement is, couldn't you set it up because such as you have basically some kind of stub or something that says, I'm calling this function and tell that function to make sure it puts something in a CP register. I actually don't know what happens when you do a jump, whether you guarantee that. If you're jumping to another function, I don't know if you can guarantee that. Let's take this offline, I don't have the answer. I know why you can do it in this. This one makes sense, it's just unrolling. The function call thing I think screws things up but I don't have a good answer. We talked to Prashan about this because he's actually looking at this now. Okay, all right, so again, the processing model is how we're actually, we have a query plan, how we wanna, how we're going to have the different operators get data from the children. And then the bottom up versus top down tells you where the data flow goes. And then the processing model tells you how much data each operator is generating. A single tuple, like the volcano model, the entire thing, like the materialization model or some subset in between, like the vectorized model. So now let's talk about how we actually wanna execute queries in parallel. So again, we're not talking about within the snippet itself for an operator how we execute that in parallel. It's just now how we organize different operator instances in parallel running in our system.  So there's two, a couple different types of parallelism. So there's interquery parallelism and interquery parallelism. We've already sort of talked about interquery parallelism. It's basically we're gonna have multiple queries running at the same time. And we talked about how the system can schedule this, you know, using a task queue and then having the different cores take things out of task queue and run them. So again, this is basically, again, multiple queries from different transactions are running at the same time and we have to sort of load balance them. And if we're doing updates, then we already know how to do concurrent control if they're updating indexes, we already know how to protect, you know, make sure it's thread safe. So we already know how to handle this in both the cases when they're read-only or when they're updating the database. So there's not much more else we can say about this. The one thing I'll also say too, is to the best of my knowledge, no matter what processing model using, like whether it's materialization or the materialization iterator or the vectorized approach, or how you organize your workers, whether it's a single worker per process or multi-threaded, right? As far as I can tell, no one concurrent control scheme is actually easier or harder to implement based on these decisions. They're all, it's all sort of the same. The one that's probably more interesting to us though is intro query parallelism. Again, how do we take a single query and have multiple operator instances running in parallel? So we can do this either horizontally or vertically. So enter intro operator parallelism or enter operator parallelism. So within a single query, how can we execute multiple operators for that query in parallel? So I would say that again, what I'm describing for both horizontal and vertical, these aren't like either or. Like if you say I'm gonna do a horizontal parallelism, doesn't mean you can't do this one. You can actually can do both of them. There's no reason you can, right? And for every single operator you can have in a relational database, all of these can be implemented in either way. Some of them obviously have more benefits. That's sort of the pipeline breaker stuff. If my operator can't proceed until it gets the full output of its children, then the vertical parallelism actually doesn't help you that much. But everyone for the most part can execute this one. So first one, horizontal parallelism. The basic idea here is that, again, we're gonna break up a single operator in our query plan or sort of replicate it into multiple instances. And each of these instances are gonna operate on a different subset of our target data. The target data could be either from a table or it could be from the output of another operator, right? And another way to think about this is we talked about morsels last time. Like you can have each operator instance could be operating on a different morsel from a table. So the way we're gonna organize the system is through this new sort of synthetic or virtual operator in a query plan called the exchange operator. This comes from the volcano paper. This notion of an exchange operator for parallel execution is what is defined in the volcano approach and that's why they call it the volcano processing model. The basic idea is this is gonna act as a barrier that's gonna prevent other operators above us in the query plan from starting to execute until we get all the responses from our children. Again, this is another example of a pipeline breaker, right? It's just, again, it's just a way to have everything be, I know I need to get the output of everybody and have it be, and wait until that they're all finished. Now, it's not to say that they're all gonna be stored in the same location inside the exchange operator, it's just sort of bookkeeping to know that everyone has generated all the data they're gonna generate.  So let's see a really simple query, same query we had before, we're doing a join A and B or now we have a predicate on A and a predicate on B. So the first thing we're gonna do is for our query plan here, we're doing a scan on A. So let's say we break A up into three different morsels. So if we have three different threads, whether they're on the same sockets or different threads or different cores, it doesn't matter. These three threads are gonna operate on these three different morsels. And then now we actually see, we can actually incorporate some more parts of the query plan into our task because we wanna get better pipelining effect. So rather than having the scan on A and then feed that output into another task or another operator that does the actual filter, we'll just say that this thread within a single pipeline will grab a tuple from A and then actually run through the filter process. And actually we can actually also include the projection up here, because if A is a really wide table has a lot of tuples and we're not a column store, we don't wanna be passing up the entire tuple from one operator to the next. So maybe we'll push down the projection as well. All right, so now again, this now represents a single task in our pipeline. Scan on A filter and then do the projection just to have just the data we need to actually do the join. Then they're gonna build our hash table because we're doing a join. And again, there's no relational operator to build a hash table, it's just a join operator. But again, they're all gonna do this. But then now they're gonna feed this into the exchange operator. And again, think about this. We're going down the left side of the tree here. We can't actually start computing the join until we have our entire hash table because otherwise we would have false negatives because something that maybe should have matched does a look up in the hash table and doesn't see anything because we haven't finished building it here. So the exchange operator again is saying that I can't proceed anywhere as up in my query plan. I can't start producing the output of my join until all of these guys have produced their entire, process all their data that they need. So again, I'm not saying that these things are separate hash tables or that it's all right into a single hash table and they're passing hash table in the exchange operator. It's just a bookkeeping thing to know that I have to wait till these guys actually finish. And then we have now on the right side of the join, again, we break the up into three morsels that are gonna do the filter and then do the same projection. But then now they're actually gonna probe into the hash table. So these guys won't get fired off until I know I've completed my join here. So again, this is where the internal bookkeeping comes in, these guys are dependent on this one. So these guys can't execute until this guy, the exchange operator has told him that everything's done. But then now we can run the join and out parallel.  Once these guys finish, actually no, in this case here, the reason why it's not an exchange operator, because this is actually a single pipeline here. So from one thread, it's gonna do the scan on B, the filter, the projection, then probe the hash table to see whether you have a join and then if there's an output, it produces that output in some output buffer here. But now I'm gonna have these three threads running parallel and these output buffers then need to be coalesced by this exchange operator up here. So I'm not showing this too well, like these threads basically stop here. Then new threads or the same threads can start running these tasks and they'll stop up here, the exchange operator here. And then once the exchange operator gets all the results from my different threads, then it can produce the output to the rest of the part of the query or actually to the client here. So this is clear. So this exchange operator is in different code bases, it won't be called exchange, right? But on the academic side, this basic idea of coalescing things and blocking other threads from proceeding in the query plan until you get all the results, it's called an exchange. All right, the other type of parallelism is interoperative parallelism. So this is where, again, we're going to have in a single query plan, we could still be executing different operator instances in parallel, but we're also now going to be executing different parts of the query plan in parallel on different threads, right? And the idea here is that you're gonna have one thread sort of spinning that for loop from the snippet I showed in the operator. It's just waiting for the output of a child. When that child emits it, it sort of hands it off to the queue from its parent and then it can go back and start maybe processing more data in its form of loop while the other thread can then process the thing it was given and continue with that, right? It'll make more sense when I show it at a high level. So I would say that this approach is not widely used as far as I know in traditional relational database systems. Where you see this is in the stream processing systems like Spark, Kafka, Flink and a bunch of other ones, right, because in these worlds, you have these like source and sync concepts. Where you have these like sync operators are generating data that can then be, sorry, the source operators generate data that then pass to syncs who then process them and pass them on to other operators. And each of those guys could be running on the same machine or different thread or to other machines that you sort of farm out and scale horizontally that way. But within the query plan, you're scaling vertically or at least your parallelism. Right, so same query plan we had before but now we say for this join operator here, right? Say we're doing a really simple nested loop join, right? For every single tuple on the outer side and every single tuple on the inner side, admit the output based on the join, right? So I could just be spinning this thing, every single time I get a tuple from the right side, every single time I get a tuple on the left side, then do my join and then it produces an output that then sends up to another thread that's just spinning, waiting for output to come out of this guy and then actually do the final projection and then produce more output, right? So again, like it's not gonna be spinning all the time, and this will be a blocking call but think of like I have one worker thread dedicated to running this snippet and another worker thread is dedicated to running this thing, right? And again, I can scale these out horizontally, have multiple instances of these operators running different threads, right? So that like I'm doing this join as many threads as possible, but the idea here is that I, every time I admit here, this is a non-blocking call, this guy goes back and goes get to the next tuple and cause some other workers gonna crunch on this, right? And again, it stalls, I guess it's a stalling call so you're not like burning the CP while you're doing this. All right, so some finish ups and last thing. So the coming up with the right number of workers we actually wanna have in a query plan is a hard problem. This is sort of the scheduling stuff that we talked about before, right? We had this notion of these different thread pools can steal data or tasks from other thread pools. How you organize that is highly dependent on the organization or implementation of the database system. And this is usually something that's like, you base it on the number of cores in the CPU that I have minus some number for back on task or maintenance tasks. This is something that you usually tune, the default usually is like, I have this many threads and I wanna use this many workers for it. How you can actually allocate the workers is sort of the scheduling stuff we talked about before. So easiest approach is that you have one worker dedicated to a single core and this is where you use task set or a set affinity to make sure that nobody else runs on your same core. So you always have, you never context switch at your core, you just sort of spinning through and doing as work as fast as possible. The alternative is that you have multiple workers per core and this looks into the pool stuff we talked about before and the idea here is that if you have one thread get blocked because it has to require some resource, whether it's disk or memory or CPU or sorry, or disk memory or network, then other threads can start processing work and still make full work of progress. So there's no one approach that's better than another. For OOTP, at least in HStor and BoltDB, this is what they used, this is what Hyper uses as well, but a bunch of other systems do this. I don't have a strong opinion that one is better than another. How we're actually gonna sign tasks for our workers is that, again, either push or pull and this is the stuff we read about last class for scheduling. Do I have my threads basically say go to a single queue and pull data out or pull task out and execute them or do I have a centralized coordinator pushing work to them? Again, no one approach is better than another. I don't have a strong opinion about this. I'm good to say do what Hyper does and they're doing a pull, but I don't know whether that's better. All right, so finish up. The main takeaway here and will be a reoccurring theme throughout the rest of the semester is that oftentimes the way we as humans organize our code and our system is actually gonna be the worst way to do this for performance. In order to overcome this, we have to be aware of what our CPU actually looks like. One of the pipelines, how much cash do we have, how the different sockets are set up and that's not always gonna be easy, but again they pay us a lot of money to build these database systems so that's fine. And then in my opinion, the one thing I do have a strong opinion about but it's not like a controversial opinion because the science clearly shows that this is the case. The vectorized bottom-up execution approach is the right way to do OLAB execution and for O2D queries is actually not a bad approach either because the query plans are usually quite short and they're not like super big. So this is what we did in Peloton and this is what we're doing now in our new system. Okay, so any questions about this? All right, so next class. Next class, the paper from Hemmier Reed is actually, I think it's actually one of the most important papers in database research community that came out of the West and one of the most important ones that came out in the last two years, right? It's, yeah, I don't want to spoil it for you but basically like it's actually now in production in SQL Server 2019. Like it was so good, like the turnaround time from Microsoft's like, oh shit, you guys wrote this paper to actually putting in the full system was like a year. It was that good. And nobody else does this and I'm sure there's patents all over it and no one else is gonna do it for a while. But the high level thing we're talking about next class is pushing more complex logic that the application wants to do to now run that inside the database system itself. So, user defined functions, stored procedures, are ways to do things that you can't really express in SQL but do it in a functional form and have the data system execute that efficiently.  It's awesome. Yeah, so I highly recommend reading this thoroughly but we'll cover in details on Monday next week. All right, any questions about this? All right guys, have a good weekend.


okay got a funny little story to tell you I had to pull out my old turntable my old record player for another project which you'll see a little later and to test it I reached into my old storage box of record albums and the first one that came out just happened to be the old Devo new traditionalists album from what 1981 so I used it to test the record player and number one I was reminded how good this album was how good the music really was I mean it includes includes tracks like through being cool and jerking back and forth and beautiful world some real some real classics from Devo that were big hits at the time too and I was also reminded about how many how many goodies the Devo albums always included well in this case I had stuck my old copy of the the single of working in the coal mine looks like it's got to work in the coal mine on both sides and also the this bizarre poster it's a freaky freaky poster that depicts Devo defending all the multicolored children of the world from I guess the Ninies and the Twits from we're through being cool but the thing that struck me with the most nostalgia was this the the paper sleeve that the record itself comes in had this this list of goofy Devo items to order clothes t-shirts hats postcards more clothes 3d glasses it's got this this big elaborate order form on the back the the plastic pompadour of an audio cassette the I remember looking at this is something I had completely forgotten until I saw it again now but I as as I looked at it I recalled reading every word of this and looking everything over and wondering if it was real and I remembered that I had come to the conclusion that this was a joke that these were not real items they're so silly but anyway the the one that caught my eye was this one down here what a flicker button demonstrates what it means to be Devo well what what is it is got this crude little drawing you can't really just like all the others you can't really tell in detail what it is it says it's a flicker button at the time I had no idea what that meant I thought maybe is this like a one of these carnival tricks it's got this this woman with huge boobs here and you you push the back of it and they and they swell up like balloons like like well anyway I decided it was all a joke anyway but this being the 21st century with the internet at all I decided to go online and look and yeah this all this stuff was real you can find all of this stuff for sale on eBay so a few days later I got my button and here's what it is it's a little girl with balloons not boobs balloons and this is what a flicker button is by the way this looks much better on camera than it does to the naked eye fact it looks amazing on camera to the to the naked eye it's it's not good at all it's very cheap anyway look at the size of this thing it's like two inches across it's made out of metal TM Musador TM Musador BV very view by pictorial productions incorporated mountain Vernon New York it's in great condition it works well and there it is well you win this round Evo it took 30 years but you got me see you next video


Cool, man. I almost want to just put that on man. I don't want to drink all that. That's so good. I Want to save it. I want to take like baby sips baby sips Okay, what how I'm gonna make these stairs. Should I make about the same as none?  How you doing dude? Thanks for coming by Yeah You know what let's put self-repair on this I Need leather right for a bookshelf. I think I have leather For leather. I definitely don't have paper and paper is from wood right Is he right? Chat how do you um? You can't search this can you I just need paper Why is this thing shuffling like a game show? I was just showing different colors There we go paper. Oh I need sugar cane for paper not wood and there were sugar cane The I think it might be gone now There's some right there Some near your house had to born a boy. Okay?  No, Mel did what? What do you do up bedtime? Where do I go from the boy on the board to your house? Oh, there he is I See you. I see you. I just need enough to make a few pieces of paper And some to start my own farm too Probably get I did to do that I just take three days Thank you, sir. I think that's enough take all you want. No, I'm not gonna get super greedy. I just need one bookshelf I think so and just need you know a few of these to start growing it myself So I can click this in search you say Then work Clicking that nothing. That's nothing. All right. Let's just look for a bookshelf. I have special eyes look Look with your special eyes My brand There once was a boy named Buona you couldn't find the book chef click to the right of it. Oh Whoa ish longu Just gifted a sub to Kira Kuru Kamura Everybody shows some love to chat. Thank you so much for the support We're just along go gifting that sub appreciate it man. Everybody show some love. Thanks. All right book shelf She's showing all This isn't this isn't working.  It doesn't seem like it has every block in here How am I gonna do this? Because I should just go boom Like that, right? And then you In a while said this sugar cane just build all around that, right? It's all have to be touching water. I thought I Think sir Let me see your war face Sir, all right, let's go in here And go to sleep So I still need the XP for it, but thank you for a yeah Iron pickaxe cannot be upgraded. Are you three?  I thought you only need to I should probably put that on my pickaxe too, huh? Oh, I got a craft another one because I've crafted that before we got the mods Alright Well back to my mine They call it a mine They call the mind chat. So this self repairs, right? So that's the idea Occasionally I'm still gonna have to repair it. I'm imagining new recipes unlocked They might have worked on or Ankle works on coal too Yeah, there's only two chat Thank Wait, I got 20 Anybody like some sub cake? Where's the cobble? Hey, oh here Wow, that was a lot of a that was a lot of coal sir Oh, that's sir that sir that silk touch No, I got a So for why do I silk touch? How do I get silk touch is that random? I don't know how I got silk touch Ain't do that special today If I did Sir, that's sir every time Every time chat can be random from upgrades whoo cool. I definitely need to keep this thing Upgraded I don't want to break Double two um so I gotta go back they give me all that coal Kappa Las Vegas it did Like one little block with all the coal. It's so good. Whoa. It repaired They repaired just now. I came back to get something Wait a minute gave you core or blocks. How do you get coal from this? I have to place all this and break it Wait, that was a ghost of a niffin. Why I gotta place all that and break it Whoa, what's all this? eggs chat That's a lot of eggs mine again mine But where'd it go? Do could do could do could do could do could do Scooby-Doo be do Hi Vane mine with a normal pick. Oh with a normal pick. Don't judge me. Don't have a normal pick actually do ye Don't you point a boy at me? I will cut the wait this mess.  I got diamond where I got diamond from Who diamond me? Somebody diamond me chat sir. You can get it randomly from digging up and leveling up your tools Like silk touch gave me a diamond just light of nowhere Sir, are you kidding me? I got so much stuff. I don't know dude dirt. We're up with dirt. I put dirt in here That's thin Somehow I have a lot of student Sir, I Need to go finish. Oh, I came in for iron. That's what I came. Okay to repair this thing. I Was like why not come back here. I honestly didn't remember.   I did This I got the XP for it. I think Vane mine is kind of good Sir, all right, we're good. I'm kind of tired of saying that myself Pretty soon.  All right, you can repair yourself now Please I guess I gotta do it this way. I don't know why stairs do that.  What up? All right. That was the last sir. Sir. Okay. That was the last sir No more sirs after this got it. No more sirs jet That was the last one sir Oh God He did it. You did it. I thought I was I swore off the sir. You made me sir chaos Everybody's showing some love in the chat. Thank you so much chaos I swore off the sir you made me sir sir. Oh, he made me sir chat So what I get on it Reinforced I Guess that gives me some durability We'll repair this thing right now This little iron pickaxe is gonna carry me the in game. What's all this? Oh, I broke it. I didn't repair it chat. I Didn't repair it All right, so what are all the colors chat? They're green Do I have a command for colors? Okay, so the command the colors are green pink red blue Aqua is it aqua? Yeah, aqua. I guess I could just open it up


With the Golden Globes out of the way, it's time for the adults to enter the room, as the Oscars looms on the horizon. If you're one of the few proud owners of a cable package still, you can watch this whole event take place on Sunday, March 10th. The rest of us who stream things, you know, we're gonna try. We're gonna try to find it.  That's the dream. You know it's not the dream, though. The 10 shocking, terrible things that took place during the nomination process. 10 egregious, unforgivable snubs, or just random weird choices for nominations took place today, and I want to talk about them. So strap in. I have a top 10 list for you. It's never been done on YouTube. In the number 10 spot is Jake Gyllenhaal's best actor snub for Nightcrawler in 2014. I'm still not over it.  It was a gritty, grounded, fantastic performance from a weirdo character Gyllenhaal's portraying. I loved it. It's a great movie. It was a great acting performance. He was snubbed. All right, now on to the real ones. At number, that council, that's number 10. At number nine, Oppenheimer's set to make history as it will be in a top contender spot for the most Oscars ever won ever. With a whopping 13 nominations, it's Oppenheimer's to lose. And I do honestly kind of hope it loses in this department, which is best supporting actress going to Emily Blunt. If I could be Emily Blunt with you. I think this actress is great. I love her. I celebrate her entire catalog. But in Oppenheimer, a movie that is phenomenal, I thought she was the weakest link in this fence. I thought her performance felt off from everyone else's. It felt out of place. She looked a little odd too, like she had some recent face creams added or a face lift or I don't know what's going on. But something was just off with her in this movie. So to put her in a best supporting actress category, it feels like a courtesy because they have so many other gnomes already. There were some fantastic animated films that came out this year. And then there was also The Boy in the Heron, a movie that is of course up for best animated film along with Elemental and a few others. I did not care for that movie. Obviously it looks wonderful, but I thought the story felt very flat. It seemed all over the place with the messages and the symbolism. I get that it's Studio Ghibli. I get this is the director's last hurrah. So you almost put it up there as a courtesy, but I just don't go for that. I don't play that way. I thought Teenage Mutant Ninja Turtles Mutant Mayhem had fantastic visuals and it was a better movie. It was one that was engaging for all members of the family, young and old. The Boy in the Heron felt like it was some personal project that was only going to be connecting with the dude that made it.   If Barbie can be up for eight nominations, Ninja Turtles can be up for best animated. Let's continue. To show what an incredibly fair and unbiased person I am, I have Asteroid City up here for worst snub in production. I don't even really like Asteroid City. I thought the movie was a little too out there. It didn't really hit any of the notes it was going for. Not awful by any means, but really didn't work for me. Wes Anderson is very hit or miss in my book, and this was a big miss. But when it came to the visual look, the set design, the costumes and everything, perfect. Why is this not up for production design? I don't understand. It just seemed like a no-brainer. This is production design 101 here. It was a very unique setting. It's the only other movie besides Barbie that really felt different from most of the other competition. A massive miss, I think. Indiana Bones in the Dial of Destiny is not a good movie. It's just kind of a pointless affair all around. And John Williams, again, it's another one of those last hurrah sort of situations. So they have him on here for musical score. Williams is one a million times over. It's not like he's due for a win. He doesn't need the W. And I didn't find the music in this one to be very captivating, especially when there was four other Indiana Jones movies that have better soundtracks. Not to mention the fact that he did Jaws, Hedwig's theme in Harry Potter. He's got Star Wars under his belt. John Williams is an absolute legend. Putting him on here for the sake of it seems like what they did. I think that there's other movies, though, that could have been put in this position. Williams could have just rode off into the sunset with Indy on this one. If anyone is familiar with getting snubbed at the Oscars, it's Leonardo DiCaprio. The man lives and breathes it. Eventually getting a courtesy win for The Revenant, a movie that was, I love that film, obviously, and I thought DiCaprio was great in it, but he's done far better performances in the past. It felt like a Denzel Washington award at this point. Another guy who made so many great movies, and then finally they caved and gave him one for a lesser performance. And now here we are again in 2024 with the Killers of the Flower Moon, Ernest Burkart's character, and he's gone. He's MIA from the list. Get DiCaprio in here. What is going on over there? Most people that I've talked to in my head, they're made up people, they really like the holdovers. I really like the holdovers. My family really like the holdovers. So why in the hell is Alexander Payne being held over for Best Director? The movie was terrific. It was a breath of fresh air. When every film coming out now seems to be like, look at me, look how different I am. I'm subverting expectations, or I'm going away you didn't want me to. That's redundant. That's kind of what subverting expectations is. The holdovers is a tried and true, formulaic picture done so well, you can't help but fall in love with it. And I know, I say formulaic, it sounds like that's a bad thing. Well, no, we have a formula for a reason. It works. And more often than not, now it seems, movies are trying to get away from that, the whole beginning, middle, and end. Instead, they just have a mishmash of different ideas and concepts that are half-assed and half-thought-out. And sometimes there's not even a conclusion. Sometimes it's a to be continued after watching a three-hour film. That's not satisfying. The holdover is, however, very much was. And so it's very sad to see that he's not being recognized for that.  Yet, Margot Robbie, MIA, not in the best actress category. Even though her costar Ken, aka Ryan Gosling, he's very much up for best supporting actor. Baby Goose is on the ticket.  It's her movie. And she does a dynamite job. Not only is she smokingly hot, as Barbie, go figure, right?  She's crying. She's giggling. She's running the whole gamut of emotions. And there's subtle ones too. It's not over the top. It is a subdued performance. It's very paired back when it needs to be. I thought she was just lovely in this movie.  So why is she missing? It makes no sense. Well, it makes no sense to us common folk. But if you're the Academy, it fits right in with my next pick.  Barbie is up for best picture. But not up for best director? What? How is Greta Gerwig getting snubbed again? This makes no sense. The movie doesn't work without the director attached to it. She's the one leading the charge. She's the one that's helping come up with the visual style, the way the actors are performing, the way the music is entrenched into the film, the way everything flows. How can you leave Greta Gerwig off best director? It makes no sense. The only thing more egregious on this list than the previous stated ones is that freaking iron claw, the 824 produced movie, is nowhere to be found anywhere. Someone dropped the ball over there at 824. Not getting this thing noticed. Because I thought Iron Claw was not only a phenomenal movie last year. It was the movie of last year. It was my number one pick for best picture. The movie has heart. It has emotion. It has drama. It's visually stunning. The actors are fantastic. I just, I can't think of a negative in the movie other than that it ends. And I don't get to spend more time with these characters and to see how things really play out for them.   It's disgusting. It's preposterous. If I could be so bold as to say, it's redonkulous. And there you have it, my top 10 most disappointing things to come out of this so-called Academy Awards. It's absolutely despicable. And hey, you know what else is missing? Saltburn. Where's Saltburn? They couldn't find a single pocket for this thing to fall into. It was a good movie. It deserves a little bit of recognition. But whatever, at the end of the day, these are guys just giving each other stickers, okay? Giving each other smiley faces or giving each other an A plus with a circle at the end, maybe a bonus point gets thrown on. It doesn't matter. We all like what we all like. We love what we love. We hate what we hate. So some of these movies are gonna bother you. Some are going to be right up your alley, McBeal. I, for one, don't really even watch awards anymore. I haven't watched them in quite some time. I am still fascinated, of course, because I'm a movie channel. I'm a critic. I love this. It's a hobby for me. It's a passion. And if you enjoy listening to me ramble on for a while, I would love if you subscribe to the channel at Adam Does Movies. Throw a like on there. Hit the notification bell. Comment below with your biggest amazing wow moment of this whole thing. Big snub, big surprise. Throw it in the comments. I'd love to see it. And also, if you really like what I'm doing and you're trying to figure out a way to help support this hobby of mine, join me on Patreon at patreon.com slash Adam Does Movies. There's a $1 tier, a $10, a $30. It goes up to $100, I think. It's wild over there. Or you can hit the Join button on YouTube and become a member that way.  It's a great time and it helps me in the channel. All right, that's all I got. Hopefully I see you soon. Take care.


What's good George Boar Ross back again with another video, so we're gonna check out ten embarrassing Roman Reigns moments WWE regrets I Can probably tell you hopefully there's the clip of Roman cutting that God awful promo in his babyface days as the big dog That's my co used to say so annoyingly probably before I meant to say it The suffering suck attached promo. It has to be in here, right?   So we're gonna check this out by none other than a stunned by wrestling appreciate all love and support Should be a good one As of January 2023 Roman Reigns has been the WWE Universal Champion since August the 30th 2020 a whopping two years and four months the tribal chief is on the run of a lifetime And in my opinion has proved himself as one of the best top-line heels in a very long time Oh sure all his head of the table for sure I've been said he's failed run as main event babyface was a disaster on almost every level and Contacts that WWE and Roman himself would probably like us to forget But in life we should all try to stay grounded and remain humble by remembering the lessons We learned in the past those moments that keep us awake at night through sheer embarrassment I've handily compiled a list of ten of the most embarrassing moments so far from the career Roman Reigns They're wrestling fan, then you will already know how close we hold the Royal Rumble to our hearts For many fans, it's their favorite date in the entire Wrestling calendar and even for lapsed fans alongside WrestleMania They're kind of like the two times of year that they're drawn back into wrestling What I'm trying to say is don't mess with our Royal Rumble Casting air minds back to 2015 Daniel Bryan mania was still gripping the WWE universe Brian had recently returned from neck surgery and fans were hoping that he would reclaim his spot on top of the Maintain something fans were expecting him to do from the number 10 spot in the Royal Rumble match Which would have been ladies what fans were invested in and while predictable It would have been the result that sent them home happy. Unfortunately. Yeah, if they would have pulled an audible again And had Daniel Bryan win that winning all that would have been great People would have loved that But I didn't happen to me Brian was eliminated after about ten minutes and everyone was stunned when Roman Reigns Entered the match at number 19. The arena erupted in booze and jeering Nobody wanted to see Reigns dominate and win this thing Some hope was restored when the fans second favorite Dean Ambrose entered at number 25 But no Reigns went on a rampage and even eliminated the fans third favorite Rusev and went on to win the whole damn thing Even the rock looked embarrassed to be standing next to Reigns as he came out to raise his arm And he did nothing to stop the booze the WWE Network was still in its infancy in 2015 and a huge benefit to all of us for just 999 a month especially before the novelty wore off and yet fans were so outraged by the result on the night They took to Twitter in their thousands using the hashtag It was one of the most misguided bits of booking ever devised by WWE had only made fans rally against WWE's chosen hero even more Reigns promo work since he's turned heel has been Proving to be I knew it had to be on there.  Good guy. You're really natural believable bad guy in his interviews and promos But the same can't be said for the many promos he cut during his baby face Frequently Jocina would outclass him on the stick during their back and forths and considering how highly contrived and scripted WWE's promos are I hope they fired his script writer Perhaps that was the problem the material Reigns was working with was a bit too wooden and not in line with his true Self one promo that sticks out as being ultra embarrassing was the one between Reigns and Seth Rollins in January 2015 Reigns called Rollins a sniveling little suck-up sell-out full of suffering suck attached if WWE were trying to make Reigns look like a friend chump on the block then this weird line Certainly helped even respected WWE writer Brian Gerwitz warned his bosses at the time that scripting. This was a bad idea Wow, I was consulting WWE at the time. I saw suffering suck attached in the script Oh, I was just like sending out flare guns like no don't have you say that there's no good way You could say that oh Reigns did and the WWE universe collectively felt secondhand embarrassment for the poor guy It was a nice cold When someone says hey, don't have him say that and you still have him say that It's it's like you didn't want him to get over with the fans match So bad that the Undertaker was apparently disgusted by it and actually apologize to Reigns for it So this isn't all on Reigns He did Troy's best here But the match between him and the Undertaker in the main event of WrestleMania 33 in 2017 was just awful No, the build-up to the match was based around Reigns Eliminating the Undertaker in the Royal Rumble and declaring that WWE was now his yard what with him being a big dog and all Bard match and things fell apart from the opening bell and went downhill from there quick with botched power bombs Undertaker not applying his submission move properly and a very awkward reverse tombstone It was like watching the phenom falling apart in front of their eyes Reigns Predictably won the match not that it would have helped for Undertaker to win it particularly and the fans booed and booed and booed This all happened because the Undertaker couldn't just let the business go and retire Gracefully and it's a shame that Reigns was dragged into this mess of a match in the first place in a feud that felt like it lasted forever Tussled with Reigns across five premium live events at the end of 2019 and the start of 2020 some cool funny scene Baron Corbin was the last guy to pin Roman Reigns the worst feud of 2019 and that's a year that also featured the crap Miz vs. Shane McMahon battle Across those five matches between Reigns and Corbin Reigns would suffer the Indignation of losing to Corbin twice and the fans quickly started to lose interest in the feud early on Facts the promos between the men were all for to droating on week after week and Eventually, they realized that the fans were basically falling asleep at ringside having to listen to this nonsense So they decided that it was time to spice things up and get people talking again Because Reigns was referring to himself as the big dog WWE cleverly decided to introduce dog food into the equation and so on an episode of Smackdown Reigns ended up handcuffed to a ring post and showered in the stuff Reigns would eventually return the favor to Corbin a few weeks later The feud was rubbish and it was a disgusting way to forward the storyline. Here's something that WWE will never mention again It's the time that they had to suspend Roman Reigns due to a violation of the company's drug testing policy in June 2016 it was reported that Reigns tested positive for Adderall, which is a banned substance in WWE without a valid Prescription Reigns was the champion at the time and quite rightly they made the decision to strip him of the title And so Reigns hastily lost the belt just days before his ban to Seth Rollins at the Money in the Bank show Thanks to his positive result Reigns would also miss the build-up to the longer-waited triple threat match between the former shield members at Battleground after being caught out Reigns tweeted I apologize to my family friends and fans for my mistake in violating WWE's wellness policy no excuses I own it some commentators at the time thought the policy violation would put an end to the Roman Reigns push in 2016 and to be fair the company did punish him when he came back by demoting him to the upper mid-card for a couple of months Anyway, and then it was back to business WWE has played up the relationship between Reigns and The Rock on many occasions Including that disastrous time he won the Royal Rumble that we mentioned earlier and no doubt They will play up their tribal connection again when the inevitable feud between the pair takes place However, it is a fact that Reigns is not actually Biologically related to The Rock no matter how much everyone goes on about them being cousins Reigns is part of the Ano'i family the famous wrestling dynasty consisting of the likes of Yokozuna Rikishi, Umaga, the Usos and others but The Rock is not actually a member of that family You see back in the day Reigns's granddad was best friends with The Rock's granddad In fact, they were so close. They considered each other blood brothers Which brought the two families very close together Due to this the Rocks family are considered to be part of the Ano'i family, but they're not really cousins They're not actually related by blood and even if they were actually part of the same family The Rocks mom was an adopted daughter of Peter Moivir So they still wouldn't be blood related. So when it comes down to the Rock and Roman Reigns being cousins It's just another work in the wacky world I didn't even know that Anderson I really didn't know that I thought they were like legit all family But I mean their family like extended family not really family but close like family So you can kind of get away with that, but I didn't know they weren't actually blood That's crazy The shield are one of the greatest factions in history and remembered for making a huge impact on the company When they debuted at the Survivor Series in 2012 In the main event of that show the shield interfered in the main event triple threat match between CM Punk, John Cena and Ryback For the championship smashing Ryback through a table with the triple powerbomb that they would become famous for The trio were a dominant force in six man tag matches going forward and out of Ambrose, Rollins and Reigns It was initially impossible to see a true leader of the group They were considered equals each important to the team in their own way However, Reigns was not a first choice to be part of the group on their debut They were meant to be mercenaries for CM Punk a literal shield for him In fact, it was Punk's idea to put the team together in the first place as he pitched the idea while he was the champion in 2012 The idea was that they would help him retain his title CM Punk revealed his initial plan for the group in a 2014 interview where he said I took the idea to Hunter, I took it to Vince, they agreed Vince was immediately like who do you have in mind and I said Ambrose, Rollins, Chris Hero or Cassius Ono Hunter shot down Hero Reigns was lucky then that Triple H had put the ideas for the group and decided to go with him instead Yeah There was a time when everyone hated John Cena 2017 was not that time No, by 2017 John Cena had come full circle and fans were largely on his side Perhaps seeing that the grass was greener with him than it was with Reigns as their lead babyface at the time Whose main event run had been going on for years by this point as the company continued to try and force him down the fans' throats Reigns had a real problem getting over as a face and the crux of the issue was his persona The fans just couldn't buy into him as he seemed ingenuine with his wise cracking jokes His awkward smile, his tilted stupid promos, spating lines that no one would ever say in real life Reigns even froze up during an in-ring promo causing Cena to ridicule him People have said that that's all the work him freezing up was supposed to happen I still am one of them people I don't know how true that is But I do believe he kind of forgot his lines, but they were saying that was that was a work That was a work for you know, he was supposed to pretend to forget his lines I don't know how true that is Reigns would go on to defeat Cena in their match at No Mercy in a result that nobody wanted At WrestleMania 34 Brock Lesnar faced Reigns in the main event and nobody wanted to see this either The event took place in New Orleans in front of 78,000 people That's 78,000 unhappy fans actually who booed the heck out of this closing match at the Super Bowl of Wrestling They say that any reaction is better than no reaction, but this can't have been fun to have to wrestle through And it certainly wasn't fun to watch WWE had tried this match once before at WrestleMania 31 in 2015 The only thing that saved that match with Seth Rollins cashing in his money in the bank contract And turning it into a genuinely brilliant and memorable WrestleMania moment No such look in 2018 the match dragged on for nearly 16 minutes with Reigns kicking out of Lesnar's F5 on five separate occasions Lesnar wrestled the same boring Super Bowl He made the move meaningless The finishing move he kicked out like five what I was like what And then he just busted him open legit gave him an elbow like he did to Randy Orton had him Fucking leaking and then won I was like what I was so confused bro Becks filled match that he'd been wrestling since 2012 and everyone was bored of seeing it Lesnar retained the title in the end not that it would have helped for Reigns to have won it At the 35th edition of WrestleMania in 2016 it was Reigns vs Triple H Heavyweight title and oh boy was this difficult to sit through years into the Reigns babyface experiment and fans were screaming at the TV and on the internet to just turn Reigns heel already but no this shitfest of a main event dragged on for half an hour and did nothing to ingratiate the big deal with the fans predictably Reigns would win the match and win the title it was a result so predictable that fans were leaving the stadium in Texas early no doubt that this slog was the shit tainted icing on the cake for a show that had dragged on for six hours Let's hope then that when Reigns inevitably turns face at some point in the future the lessons have been learned from those years where the big dog babyface was just a big joke facts i think his uh his babyface term whenever it does happen will probably be much more uh enjoyable people will embrace it more because we would have been used to his character i think it's gonna be more or less the same character is just less jokey you know what i'm saying it's not gonna be all the cringy jokes i think it will work now he can he can literally just be the same guy just a babyface that's it like a stone cold like stone cold was a babyface from the fans perspective but he would still do like heel like stuff it's just the fans loved him so he can still be the same guy be you know ruthless can be aggressive but you know the fans love and he you know he gives high fives every now and then you can still do that you don't have to change him completely you know but i i do think um whenever he does drop the titles hope is that this year's WrestleMania he'll probably take a hiatus after this whole bloodline thing kind of you know separates because i'm sure they're gonna deal with that see how that plays out probably take a hiatus and then maybe come back and we'll see how things play out so i don't know but yeah these are the moments that wwe definitely uh should regret what they did with roman cuz oh they were awful and it didn't work so comment down below let me know what was the most cringe moment from roman reigns babyface years it gotta be the suffering suckers the hash like it gotta be suffering suck attached in a promo a grown ass man saying that to another grown ass man and to be taken seriously in the main event promo segment get him off my tv get him off get him off that was the most cringe thing they ever did to roman they did him dirty man but i appreciate all love and support row 250k i'm still here in speedy youtube wrestling champion of the world and here in the cuts were heavyweight champion appreciate y'all kicking me see y'all next time peace