CTE vs Function/trigger performance in Postgresql I have a very long CTE query that I have shortened here for readability. But it tries to insert state, county, city, zipcode and street into their own tables and then insert their ID for inserting the address in the property table.

with tmpstate as (
insert
    into
        state ....on
    conflict ( lower(state_code) ) do
    update
    set
        state_code = excluded.state_code returning id,
        state_code ),
tmpcounty as (
insert
    into
        ..... on
    conflict ( lower(county),
    state_id ) do
    update
    set
        county = excluded.county returning id,
        county ),
tmpcity as (
insert
    into
      .....
    values ( 'Sarasota',
    (
    select
        id
    from
        tmpcounty
    limit 1 ),
    (
    select
        id
    from
        tmpstate
    limit 1 ) ) on
    conflict ( lower(city),
    county_id,
    state_id ) do
    update
    set
        city = excluded.city returning id,
        city ),
tmpzipcode as (
...... returning id,
        zipcode ),
tmpstreet as (
  .... ),
tmpproperty as(
insert
    into
        property (full_address,
        street_address,
        street_id,
        city_id,
        state_id,
        zipcode_id,
        county_id,
        property_details )
    values('ssss',
    'ssss',
    (
    select
        id
    from
        tmpstreet
    limit 1),
    (
    select
        id
    from
        tmpcity
    limit 1),
    (
    select
        id
    from
        tmpstate
    limit 1),
    (
    select
        id
    from
        tmpzipcode
    limit 1),
    (
    select
        id
    from
        tmpcounty
    limit 1),
    '{}') returning id)
select
    id
from
    property
limit 1


Would there be any performance gain if I create functions/triggers that insert the street, city, etc... and return their id if they exist instead of this long CTE query?
Running a big statement with its CTEs will be more efficient than running several small ones.

The only advantage of having a PL/pgSQL function for the individual inserts is that plans of statements are cached for the duration of the database session. But you can put your big statement into such a function if you want to make use of that.