Vertica configurations
Configuration of Incremental Models
Using the on_schema_change config parameter
You can use on_schema_change parameter with values ignore, fail and append_new_columns. Value sync_all_columns is not supported at this time.
Configuring the ignore (default) parameter
- Source code
- Run code
{{config(materialized = 'incremental',on_schema_change='ignore')}}
select * from {{ ref('seed_added') }}
insert into "VMart"."public"."merge" ("id", "name", "some_date")
(
select "id", "name", "some_date"
from "merge__dbt_tmp"
)
Configuring the fail parameter
- Source code
- Run code
{{config(materialized = 'incremental',on_schema_change='fail')}}
select * from {{ ref('seed_added') }}
The source and target schemas on this incremental model are out of sync!
They can be reconciled in several ways:
- set the `on_schema_change` config to either append_new_columns or sync_all_columns, depending on your situation.
- Re-run the incremental model with `full_refresh: True` to update the target schema.
- update the schema manually and re-run the process.
Additional troubleshooting context:
Source columns not in target: {{ schema_changes_dict['source_not_in_target'] }}
Target columns not in source: {{ schema_changes_dict['target_not_in_source'] }}
New column types: {{ schema_changes_dict['new_target_types'] }}
Configuring the append_new_columns parameter
- Source code
- Run code
{{ config( materialized='incremental', on_schema_change='append_new_columns') }}
select * from public.seed_added
insert into "VMart"."public"."over" ("id", "name", "some_date", "w", "w1", "t1", "t2", "t3")
(
select "id", "name", "some_date", "w", "w1", "t1", "t2", "t3"
from "over__dbt_tmp"
)
Using the incremental_strategy config parameter
The append strategy (default):
Insert new records without updating or overwriting any existing data. append only adds the new records based on the condition specified in the is_incremental() conditional block.
- Source code
- Run code
{{ config( materialized='incremental', incremental_strategy='append' ) }}
select * from public.product_dimension
{% if is_incremental() %}
where product_key > (select max(product_key) from {{this }})
{% endif %}
insert into "VMart"."public"."samp" (
"product_key", "product_version", "product_description", "sku_number", "category_description",
"department_description", "package_type_description", "package_size", "fat_content", "diet_type",
"weight", "weight_units_of_measure", "shelf_width", "shelf_height", "shelf_depth", "product_price",
"product_cost", "lowest_competitor_price", "highest_competitor_price", "average_competitor_price", "discontinued_flag")
(
select "product_key", "product_version", "product_description", "sku_number", "category_description", "department_description", "package_type_description", "package_size", "fat_content", "diet_type", "weight", "weight_units_of_measure", "shelf_width", "shelf_height", "shelf_depth", "product_price", "product_cost", "lowest_competitor_price", "highest_competitor_price", "average_competitor_price", "discontinued_flag"
from "samp__dbt_tmp"
)
The merge strategy:
Match records based on a unique_key; update old records, insert new ones. (If no unique_key is specified, all new data is inserted, similar to append.) The unique_key config parameter is required for using the merge strategy, the value accepted by this parameter is a single table column.
- Source code
- Run code
{{ config( materialized = 'incremental', incremental_strategy = 'merge', unique_key='promotion_key' ) }}
select * FROM public.promotion_dimension
merge into "VMart"."public"."samp" as DBT_INTERNAL_DEST using "samp__dbt_tmp" as DBT_INTERNAL_SOURCE
on DBT_INTERNAL_DEST."promotion_key" = DBT_INTERNAL_SOURCE."promotion_key"
when matched then update set
"promotion_key" = DBT_INTERNAL_SOURCE."promotion_key", "price_reduction_type" = DBT_INTERNAL_SOURCE."price_reduction_type", "promotion_media_type" = DBT_INTERNAL_SOURCE."promotion_media_type", "display_type" = DBT_INTERNAL_SOURCE."display_type", "coupon_type" = DBT_INTERNAL_SOURCE."coupon_type", "ad_media_name" = DBT_INTERNAL_SOURCE."ad_media_name", "display_provider" = DBT_INTERNAL_SOURCE."display_provider", "promotion_cost" = DBT_INTERNAL_SOURCE."promotion_cost", "promotion_begin_date" = DBT_INTERNAL_SOURCE."promotion_begin_date", "promotion_end_date" = DBT_INTERNAL_SOURCE."promotion_end_date"
when not matched then insert
("promotion_key", "price_reduction_type", "promotion_media_type", "display_type", "coupon_type",
"ad_media_name", "display_provider", "promotion_cost", "promotion_begin_date", "promotion_end_date")
values
(
DBT_INTERNAL_SOURCE."promotion_key", DBT_INTERNAL_SOURCE."price_reduction_type", DBT_INTERNAL_SOURCE."promotion_media_type", DBT_INTERNAL_SOURCE."display_type", DBT_INTERNAL_SOURCE."coupon_type", DBT_INTERNAL_SOURCE."ad_media_name", DBT_INTERNAL_SOURCE."display_provider", DBT_INTERNAL_SOURCE."promotion_cost", DBT_INTERNAL_SOURCE."promotion_begin_date", DBT_INTERNAL_SOURCE."promotion_end_date"
)
Using the merge_update_columns config parameter
The merge_update_columns config parameter is passed to only update the columns specified and it accepts a list of table columns.
- Source code
- Run code
{{ config( materialized = 'incremental', incremental_strategy='merge', unique_key = 'id', merge_update_columns = ["names", "salary"] )}}
select * from {{ref('seed_tc1')}}
merge into "VMart"."public"."test_merge" as DBT_INTERNAL_DEST using "test_merge__dbt_tmp" as DBT_INTERNAL_SOURCE on DBT_INTERNAL_DEST."id" = DBT_INTERNAL_SOURCE."id"
when matched then update set
"names" = DBT_INTERNAL_SOURCE."names", "salary" = DBT_INTERNAL_SOURCE."salary"
when not matched then insert
("id", "names", "salary")
values
(
DBT_INTERNAL_SOURCE."id", DBT_INTERNAL_SOURCE."names", DBT_INTERNAL_SOURCE."salary"
)
delete+insert strategy:
Through the delete+insert incremental strategy, you can instruct dbt to use a two-step incremental approach. It will first delete the records detected through the configured is_incremental() block and then re-insert them. The unique_key is a required parameter for using delete+instert strategy which specifies how to update the records when there is duplicate data. The value accepted by this parameter is a single table column.
- Source code
- Run code
{{ config( materialized = 'incremental', incremental_strategy = 'delete+insert', unique_key='date_key' ) }}
select * FROM public.date_dimension
delete from "VMart"."public"."samp"
where (
date_key) in (
select (date_key)
from "samp__dbt_tmp"
);
insert into "VMart"."public"."samp" (
"date_key", "date", "full_date_description", "day_of_week", "day_number_in_calendar_month", "day_number_in_calendar_year", "day_number_in_fiscal_month", "day_number_in_fiscal_year", "last_day_in_week_indicator", "last_day_in_month_indicator", "calendar_week_number_in_year", "calendar_month_name", "calendar_month_number_in_year", "calendar_year_month", "calendar_quarter", "calendar_year_quarter", "calendar_half_year", "calendar_year", "holiday_indicator", "weekday_indicator", "selling_season")
(
select "date_key", "date", "full_date_description", "day_of_week", "day_number_in_calendar_month", "day_number_in_calendar_year", "day_number_in_fiscal_month", "day_number_in_fiscal_year", "last_day_in_week_indicator", "last_day_in_month_indicator", "calendar_week_number_in_year", "calendar_month_name", "calendar_month_number_in_year", "calendar_year_month", "calendar_quarter", "calendar_year_quarter", "calendar_half_year", "calendar_year", "holiday_indicator", "weekday_indicator", "selling_season"
from "samp__dbt_tmp"
);
insert_overwrite strategy:
The insert_overwrite strategy does not use a full-table scan to delete records. Instead of deleting records it drops entire partitions. This strategy may accept partition_by_string and partitions parameters. You provide these parameters when you want to overwrite a part of the table.
partition_by_string accepts an expression based on which partitioning of the table takes place. This is the PARTITION BY clause in Vertica.
partitions accepts a list of values in the partition column.
The config parameter partitions must be used carefully. Two situations to consider:
- Fewer partitions in the
partitionsparameter than in the where clause: destination table ends up with duplicates. - More partitions in the
partitionsparameter than in the where clause: destination table ends up missing rows. Less rows in destination than in source.
To understand more about PARTITION BY clause check here
The partitions parameter is optional, if the partitions parameter is not provided, the partitions in the where clause will be dropped from destination and inserted back from source. If you use a where clause, you might not need the partitions parameter.
The where clause condition is also optional, but if not provided then all data in source is inserted in destination.
If no where clause condition and no partitions parameter are provided, then it drops all partitions from the table and inserts all of them again.
If the partitions parameter is provided but not where clause is provided, the destination table ends up with duplicates because the partitions in the partitions parameter are dropped but all data in the source table (no where clause) is inserted in destination.
The partition_by_string config parameter is also optional. If no partition_by_string parameter is provided, then it behaves like delete+insert. It deletes all records from destination and then it inserts all records from source. It won’t use or drop partitions.
If both the partition_by_string and partitions parameters are not provided then insert_overwrite strategy truncates the target table and insert the source table data into target.
If you want to use partitions parameter then you have to partition the table by passing partition_by_string parameter.
- Source code
- Run code
{{config(materialized = 'incremental',incremental_strategy = 'insert_overwrite',partition_by_string='YEAR(cc_open_date)',partitions=['2023'])}}
select * from online_sales.call_center_dimension
select PARTITION_TABLE('online_sales.update_call_center_dimension');
SELECT DROP_PARTITIONS('online_sales.update_call_center_dimension', '2023', '2023');
SELECT PURGE_PARTITION('online_sales.update_call_center_dimension', '2023');
insert into "VMart"."online_sales"."update_call_center_dimension"
("call_center_key", "cc_closed_date", "cc_open_date", "cc_name", "cc_class", "cc_employees",
"cc_hours", "cc_manager", "cc_address", "cc_city", "cc_state", "cc_region")
(
select "call_center_key", "cc_closed_date", "cc_open_date", "cc_name", "cc_class", "cc_employees",
"cc_hours", "cc_manager", "cc_address", "cc_city", "cc_state", "cc_region"
from "update_call_center_dimension__dbt_tmp"
);
Optimization options for table materialization
There are multiple optimizations that can be used when materializing models as tables. Each config parameter applies a Vertica specific clause in the generated CREATE TABLE DDL.
For more information see Vertica options for table optimization.
You can configure these optimizations in your model SQL file as described in the examples below:
Configuring the ORDER BY clause
To leverage the ORDER BY clause of the CREATE TABLE statement use the order_by config param in your model.
Using the order_by config parameter
- Source code
- Run code
{{ config( materialized='table', order_by='product_key') }}
select * from public.product_dimension
create table "VMart"."public"."order_s__dbt_tmp" as
( select * from public.product_dimension)
order by product_key;
Configuring the SEGMENTED BY clause
To leverage the SEGMENTED BY clause of the CREATE TABLE statement, use the segmented_by_string or segmented_by_all_nodes config parameters in your model. By default ALL NODES are used to segment tables, so the ALL NODES clause in the SQL statement will be added when using segmented_by_string config parameter. You can disable ALL NODES using no_segmentation parameter.
To learn more about segmented by clause check here.
Using the segmented_by_string config parameter
segmented_by_string config parameter can be used to segment projection data using a SQL expression like hash segmentation.
- Source code
- Run code
{{ config( materialized='table', segmented_by_string='product_key' ) }}
select * from public.product_dimension
create table
"VMart"."public"."segmented_by__dbt_tmp"
as (select * from public.product_dimension)
segmented by product_key ALL NODES;
Using the segmented_by_all_nodes config parameter
segmented_by_all_nodes config parameter can be used to segment projection data for distribution across all cluster nodes.
If you want to pass segmented_by_all_nodes parameter then you have to segment the table by passing segmented_by_string parameter.
- Source code
- Run code
{{ config( materialized='table', segmented_by_string='product_key' ,segmented_by_all_nodes='True' ) }}
select * from public.product_dimension
create table "VMart"."public"."segmented_by__dbt_tmp" as
(select * from public.product_dimension)
segmented by product_key ALL NODES;
Configuring the UNSEGMENTED ALL NODES clause
To leverage theUNSEGMENTED ALL NODES clause of the CREATE TABLE statement, use the no_segmentation config parameters in your model.
Using the no_segmentation config parameter
- Source code
- Run code
{{config(materialized='table',no_segmentation='true')}}
select * from public.product_dimension
create table
"VMart"."public"."ww__dbt_tmp"
INCLUDE SCHEMA PRIVILEGES as (
select * from public.product_dimension )
UNSEGMENTED ALL NODES ;
Configuring the PARTITION BY clause
To leverage the PARTITION BY clause of the CREATE TABLE statement, use the partition_by_string, partition_by_active_count or the partition_by_group_by_string config parameters in your model.
To learn more about partition by clause check here
Using the partition_by_string config parameter
partition_by_string (optinal) accepts a string value of a any one specific column_name based on which partitioning of the table data takes place.
- Source code
- Run code
{{ config( materialized='table', partition_by_string='employee_age' )}}
select * FROM public.employee_dimension
create table "VMart"."public"."test_partition__dbt_tmp" as
( select * FROM public.employee_dimension);
alter table "VMart"."public"."test_partition__dbt_tmp"
partition BY employee_age
Using the partition_by_active_count config parameter
partition_by_active_count (optional) specifies how many partitions are active for this table. It accepts an integer value.
If you want to pass partition_by_active_count parameter then you have to partition the table by passing partition_by_string parameter.
- Source code
- Run code
{{ config( materialized='table',
partition_by_string='employee_age',
partition_by_group_by_string="""
CASE WHEN employee_age < 5 THEN 1
WHEN employee_age>50 THEN 2
ELSE 3 END""",
partition_by_active_count = 2) }}
select * FROM public.employee_dimension
create table "VMart"."public"."test_partition__dbt_tmp" as
( select * FROM public.employee_dimension );
alter table "VMart"."public"."test_partition__dbt_tmp" partition BY employee_ag
group by CASE WHEN employee_age < 5 THEN 1
WHEN employee_age>50 THEN 2
ELSE 3 END
SET ACTIVEPARTITIONCOUNT 2 ;
Using the partition_by_group_by_string config parameter
partition_by_group_by_string parameter(optional) accepts a string, in which user should specify each group cases as a single string.
This is derived from the partition_by_string value.
partition_by_group_by_string parameter is used to merge partitions into separate partition groups.
If you want to pass partition_by_group_by_string parameter then you have to partition the table by passing partition_by_string parameter.
- Source code
- Run code
{{config(materialized='table',
partition_by_string='number_of_children',
partition_by_group_by_string="""
CASE WHEN number_of_children <= 2 THEN 'small_family'
ELSE 'big_family' END""")}}
select * from public.customer_dimension
create table "VMart"."public"."test_partition__dbt_tmp" INCLUDE SCHEMA PRIVILEGES as
( select * from public.customer_dimension ) ;
alter table "VMart"."public"."test_partition__dbt_tmp"
partition BY number_of_children
group by CASE WHEN number_of_children <= 2 THEN 'small_family'
ELSE 'big_family' END ;
Configuring the KSAFE clause
To leverage the KSAFE clause of the CREATE TABLE statement, use the ksafe config parameter in your model.
- Source code
- Run code
{{ config( materialized='table', ksafe='1' ) }}
select * from public.product_dimension
create table "VMart"."public"."segmented_by__dbt_tmp" as
(select * from public.product_dimension )
ksafe 1;