-
Notifications
You must be signed in to change notification settings - Fork 159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize insert_overwrite
incremental strategy with WRITE_TRUNCATE / Partition copy
#77
Comments
When we rebuild a day of data for one of our larger tables, the data collection takes 7 Tb and the merge takes 33 Tb to process. We regularly do the data collection into a temp table, and manually copy the partition into the table. I'd love to see this as a separate incremental strategy. Here is the copy step that we do: |
Exactly it would be much better for you to have that copy step directly done by dbt. |
I think that this is just how our process was built - build a partition in a temp table, rm a partition on the destination table, cp the partition to the destination table. I think you are right, we could just overwrite the partition by using the partition decorator in the destination table, and remove the rm step. |
Right, I tend to just |
opening this up for any work you may wish to do on it as seems after conversation with @jtcohen6 and continued on since that there is a good grasp of what to do, happy to help in any way I can. |
For visibility: @McKnight-42 and I have been discussing this over the past few days, since it touches on a whole matrix of BigQuery functionality, and a lot of the history of the With the benefit of that discussion, a couple quick thoughts:
So, just want to say — thanks for the thoughtful writeup @github-christophe-oudar (here and in #75)! Lots to chew on. Let's keep digging in :) |
Thank you both for getting back to me on those issues.
I wish it was possible to do otherwise. However the overhead is so large that it's tough to accept the tradeoff sometimes.
Do you mean that you would like to prevent user to be able to access the BQ driver through materialization code or just through Jinja macros?
I agree it doesn't need to be a default and it has to be documented.
I'd need more tries to see what's possible or not. I'd say we'll likely need one statement per partition to be backfilled.
I'm not sure what you mean: let's say we want to issue queries such as So what could be the plan to develop that feature?
|
Sorry, I was missing an essential word here: I'm not strictly opposed when there's a justifiable trade-off! We'd want to expose specific BQ python functionality, as context methods, via Jinja macros, with as much logging as we can muster for visibility.
This approach makes sense for incremental additions to the table. What I'm confused about is, when we need to insert multiple partitions at once, or recreate all partitions of an ingestion-time-partitioned table from scratch (either for the very first time, or In the older (now deprecated) method, we required users to include |
Thanks for the clarification, that makes sense! For table creation (aka full refresh), you don't really to mind it that much: it's going to be such as
As described in #75, it won't work for ingestion time partition tables but that's the point of the issue (that would be fixed by splitting that in 2 steps). I would expect people working with ingestion time partition tables to select proper partition column (_PARTITIONTIME). It would make it much easier to work with. I think we should put a warning if the request output column doesn't contain appropriate columns. Indeed BQ, when inserted without an explicit partition (ie implicit NULL on partition column), it will insert in NULL. I'd like to make it as "straightforward" as possible, hopefully I can fit all usages with that approach. However you might have a point that a dedicated provided |
After reading through #75 for the fourth or fifth time, it finally clicked for me how we're going to get the "best of both worlds" here: partition values derived from actual columns, and also the performance characteristics of older-school ingestion-time partitioned tables (+ legacySQL / @github-christophe-oudar Thank you for patience on this one! I know the delay here has been on me, and that you've got other things on your plate these days. If someone else is interested in working on this, we'd be happy to help support them. I think the right next steps are:
|
Thanks for having a thorough look at the issues. My gut feeling is that (a) is faster but a quick test would definitely assess it. |
I started to look at:
So far:
the run time is 4s (and I'm not sure it uses any slots)
with the destination table being So there is no match regarding both options (unless I didn't understand what you meant with solution b) Here how I see it implemented:
I'll look into implementing that approach on top of the existing PR for #136 in another PR if you don't see any issue with that approach. |
This issue has been marked as Stale because it has been open for 180 days with no activity. If you would like the issue to remain open, please remove the stale label or comment on the issue, or it will be closed in 7 days. |
Describe the feature
This is a follow-up from a discussion over the topic with @jtcohen6.
Let's assume we have a model with incremental materialization and we're going for an incremental run.
However the merge will first delete the data to insert the data.
On big partitions, it can take a while resulting in a long operation compared to other approaches such as:
mydataset.newtable$20211130
) while usingWRITE_TRUNCATE
setting.bq cp mydataset.newtable__dbt_tmp$20211130 mydataset.newtable$20211130
.As far as I know the fastest approach is to use
bq cp
(it might require to benchmark it though) unless you don't need a temporary table (ie no column change & single partition) in which case, you would use the input query and write to the destination table with the partition decorator directly.The main inconvenient for that approach is that even though the
insert_overwrite
strategy operation isn't fully atomic (the temporary table is created and stays even if theMERGE
fails), theMERGE
query is atomic on all partitions.So to keep the same behavior, it requires to have a single partition or accept the tradeoff of breaking the atomicity of the partitions replacement step.
Therefore it could be relevant to have a
copy_partitions
config to activate that approach.Describe alternatives you've considered
It could also be a whole new incremental strategy if relevant.
Additional context
I had a production case that I described in the thread where, using a single partition,
MERGE
version (insert_overwrite) was taking 43 minutes while the query with WRITE_TRUNCATE took 26 minutes for the same result.At Teads, our internal BigQuery query wrapper tool is using a select & write_truncate since we're not using a temporary table as an intermediate step because we only process a single partition per query (which is a specific case compared to the dbt approach). It's quite a deal breaker to use dbt as is for those queries because of that performance overhead.
Of course, it would be much better if Google could make a server side optimisation on
MERGE
queries when it detects that pattern.Who will this benefit?
It will benefit anyone using
insert_overwrite
incremental strategy with large partitions where delete/insert are long to process.Are you interested in contributing this feature?
Yes
The text was updated successfully, but these errors were encountered: