Skillnader mellan målplattformar
PDQ genererar SQL för sex målplattformar utifrån en och samma modell. Modellen ändras inte när målet gör det — samma objekt, attribut, relationer, affärsnycklar och klassificeringar ger samma lagerform överallt.
Det som ändras är dialekten under, och dialekter är inte lika kapabla. Vissa motorer upprätthåller en främmande nyckel; vissa registrerar den och ignorerar den; en kan inte uttrycka den alls. Vissa tar emot en kolumnbeskrivning inuti CREATE TABLE; vissa behöver en efterföljande sats; vissa har ingenstans att lägga den. De skillnaderna är inte defekter att kringgå senare — de är egenskaper hos den motor du valt, och de avgör vilka garantier du får från databasen och vilka du måste skaffa någon annanstans.
Den här sidan redovisar dem rakt av, per plattform, så att valet görs före den första genereringskörningen i stället för att upptäckas efter några hundra tabeller.
SQL-generatorn genererar för Snowflake, Databricks, SQL Server, Azure Synapse, Microsoft Fabric och PostgreSQL. Allt nedan beskriver dessa sex.
Översikt
| Snowflake | Databricks | SQL Server | Synapse | Fabric | PostgreSQL | |
|---|---|---|---|---|---|---|
| Läser källfiler via | Namngiven STAGE | read_files() | OPENROWSET(BULK …) | OPENROWSET(BULK …) | OPENROWSET(BULK …) | pg_lake-främmandetabell |
| Unikt villkor | Deklarerat, NOT ENFORCED | Genereras inte | Upprätthålls | Deklarerat, NOT ENFORCED | Upprätthålls | Upprätthålls |
| Främmande nyckel | Deklarerad, NOT ENFORCED | Genereras inte | Deklarerad, NOCHECK | Genereras inte | Deklarerad, NOT ENFORCED | Upprätthålls |
| Kolumnkommentarer | Inline i CREATE TABLE | Inline i CREATE TABLE | Extended properties | — | — | Endast base-lagret |
| Kategorietiketter | Nativ kolumn-TAG | Unity Catalog SET TAGS | Extended property | Extended property | Extended property | Sidotabell _column_tags |
Maskering av sensitive | Maskeringspolicy | — (endast etikett) | Dynamic data masking | Dynamic data masking | Dynamic data masking | SECURITY LABEL (postgres_anon) |
| Iceberg-publicering | Nativ | Delta UniForm | — | — | — | Faller tillbaka på vanlig tabell |
| Schemaläggning i databasen | CREATE TASK | — | — | — | — | — |
| Beräkningswarehouse | USE WAREHOUSE | — | — | — | — | — |
| Surrogatnycklar | SEQUENCE | GENERATED ALWAYS AS IDENTITY | IDENTITY | IDENTITY | IDENTITY | IDENTITY |
Resten av sidan förklarar vad varje rad kostar dig.
Villkor — vad som faktiskt upprätthålls
Det här är den skillnad som betyder mest, och den som lättast missförstås. Ett villkor som syns i genererad DDL är inte samma sak som ett villkor motorn upprätthåller vid skrivning.
| Mål | Unikt på core | Främmande nyckel | Vad databasen faktiskt garanterar |
|---|---|---|---|
| PostgreSQL | UNIQUE, upprätthålls | FOREIGN KEY, upprätthålls | Båda. En dubblerad affärsnyckel eller ett föräldralöst barn avvisas vid laddning. |
| SQL Server | UNIQUE NONCLUSTERED, upprätthålls | Läggs till WITH NOCHECK och inaktiveras sedan | Endast unikhet. Den främmande nyckeln är dokumentation som optimeraren kanske inte litar på. |
| Fabric | UNIQUE NONCLUSTERED, upprätthålls | NOT ENFORCED | Endast unikhet. |
| Snowflake | UNIQUE … NOT ENFORCED | FOREIGN KEY … NOT ENFORCED | Ingendera. Båda är metadata, för verktyg och optimerare. |
| Synapse | UNIQUE … NOT ENFORCED | Ingen sats genereras — dedikerade SQL-pooler stödjer inte främmande nycklar | Ingendera. |
| Databricks | Ingen sats genereras | Ingen sats genereras | Ingendera. Delta har inget UNIQUE, och PK/FK är endast informativa. |
På Snowflake, Databricks och Synapse hindrar databasen inte en dubblerad affärsnyckel — men ingenting skapar någon. Deduplicering på den deklarerade affärsnyckeln ingår i core-modellens genererade laddningsmönster, så core innehåller en post per affärsnyckel på varje mål, oavsett vad villkoret säger. Ett icke upprätthållet UNIQUE är metadata för optimeraren och verktygen, inte en lucka att täcka.
Det ett upprätthållet villkor dessutom skulle fånga är en skrivning som går förbi den genererade laddningen — en manuell INSERT, ett backfill-skript, ett annat verktyg som skriver rakt in i core. PostgreSQL, SQL Server och Fabric avvisar sådana; de övriga målen accepterar dem, och en QPI-kvalitetskontroll är hur du skulle upptäcka det.
Alla tre villkorsfamiljer är på som standard och styrs av ENABLE_CORE_UNIQUE, ENABLE_FOREIGN_KEY och ENABLE_PUBL_PRIMARY_KEY. Att stänga av dem är ett sätt att behålla utdata från före 3.2; det är inte ett sätt att göra ett icke upprätthållet villkor upprätthållet.
Beskrivningar och kommentarer
En beskrivning som deklareras en gång på ett källfilsfält eller ett modellattribut hamnar olika beroende på vad motorn har att ta emot den med.
| Mål | Var beskrivningen hamnar | Konsekvens |
|---|---|---|
| Snowflake | COMMENT inline i CREATE TABLE, plus ALTER … COMMENT vid ändring | Dokumenterad från det ögonblick tabellen finns |
| Databricks | COMMENT inline i CREATE TABLE, plus ALTER … COMMENT vid ändring | Detsamma, och synlig i Unity Catalog |
| SQL Server | sp_addextendedproperty (MS_Description), efter skapandet | Finns, men i extended properties snarare än i tabelldefinitionen |
| Synapse / Fabric | Genereras inte | Beskrivningar lever i AME och konsolen, inte i lagret |
| PostgreSQL | COMMENT ON i base-lagret; core- och publiceringstabeller får ingen genererad kommentar | Delvis |
Bara Snowflake och Databricks dokumenterar en tabell vid födseln — kommentaren ingår i CREATE, så det finns inget fönster där tabellen existerar odokumenterad. Överallt annars appliceras beskrivningen i efterhand eller bärs inte in i databasen alls, och konsolens genererade dokumentation är den auktoritativa ytan.
Apostrofer i beskrivningar escapas på varje väg. Inline-kommentarer gör det viktigare än förr: en oescapad apostrof skulle bryta hela CREATE TABLE snarare än en avslutande ALTER.
Klassificering och maskering
Kategorietiketter kommer från fieldDomain; känslighet kommer från flaggan sensitive. Båda genereras med den facilitet plattformen faktiskt läser.
| Mål | Kategorietikett | sensitive ger |
|---|---|---|
| Snowflake | MODIFY COLUMN … SET TAG | En maskeringspolicy applicerad på kolumnen |
| Databricks | ALTER COLUMN … SET TAGS i Unity Catalog | Endast en klassificeringsetikett — ingen mask |
| SQL Server / Synapse / Fabric | sp_addextendedproperty, en namngiven property per kolumn | ADD MASKED WITH (FUNCTION = 'default()') — dynamic data masking |
| PostgreSQL | En rad i den schemaegna sidotabellen _column_tags | SECURITY LABEL FOR anon … 'MASKED WITH VALUE NULL' |
Tre saker följer av tabellen:
- Databricks flaggar känsliga kolumner; det maskerar dem inte. Etiketten är vad Unity Catalog läser och vad styrningsverktyg kan agera på, men värdet är fortfarande läsbart. Om maskering är ett krav måste den komma från en Unity Catalog-policy du äger, inte från den genererade DDL:en.
- Snowflake förutsätter att maskeringspolicyn finns. Den genererade satsen kopplar på
default_masking_policy; den skapar den inte. Skapa och tilldela policyn före första körningen, annars misslyckas känslighetssatserna. - PostgreSQL-maskering kräver ett tillägg.
SECURITY LABEL FOR anonkräverCREATE EXTENSION anon;och dess label provider. Utan det parsar satserna men misslyckas vid exekvering.
PostgreSQL håller kategorier i en sidotabell av ett strukturellt skäl: en Postgres-kolumn har exakt en kommentar, så etiketter lagrade som kommentarer skulle skriva över varandra och över beskrivningen. Sidotabellen håller en rad per etikett, vilket bevarar flera etiketter per kolumn och låter en enskild kategori tas bort utan att röra resten.
TAG_NAME, SENSITIVE_TAG_NAME och SENSITIVE_TAG_VALUE har standardvärden som är lätta att acceptera av misstag. Sätt dem till din katalogs schema före den första genereringskörningen — att döpa om en etikett över några hundra tabeller efteråt är en migrering, inte en inställningsändring.
Datatyper
Samma deklarerade dataType löses upp till olika fysisk typ per mål. Skillnaderna är små, och tre av dem ändrar beteende.
| Deklarerat | Snowflake | Databricks | SQL Server | Synapse | Fabric | PostgreSQL |
|---|---|---|---|---|---|---|
| Text | STRING | STRING | NVARCHAR(255) | NVARCHAR(500) | VARCHAR(500) | VARCHAR(255) |
| Heltal | INTEGER | INTEGER | DECIMAL(18,0) | DECIMAL(18,0) | BIGINT | NUMERIC(18,0) |
| Decimal | DECIMAL(28,8) | DECIMAL(28,8) | DECIMAL(28,8) | DECIMAL(28,8) | DECIMAL(28,8) | NUMERIC(28,8) |
| Tidsstämpel | TIMESTAMP | TIMESTAMP | DATETIME2 | DATETIME2 | DATETIME2(3) | TIMESTAMP |
| Tid | TIME | STRING | TIME | TIME | TIME | TIME |
| Boolesk | BOOLEAN | BOOLEAN | BIT | BIT | BIT | BOOLEAN |
| Surrogatnyckel | NUMBER(38,0) | BIGINT | BIGINT | BIGINT | BIGINT | BIGINT |
- Databricks har ingen
TIME-typ. Ett fält med enbart tid kommer in somSTRING. Sortering fungerar fortfarande lexikalt för nollutfyllda värden, men aritmetik gör det inte — modellera det som en tidsstämpel om du behöver räkna med det. - Textlängder är begränsade på de relationella målen och obegränsade på de kolumnära. Ett värde som ryms bekvämt i Snowflakes
STRINGkan trunkeras eller avvisas vid 255 tecken på SQL Server och PostgreSQL, och vid 500 på Synapse och Fabric. Kontrollera det längsta förväntade värdet för fritextfält innan du väljer en relationell motor. - Typkonvertering är strikt på PostgreSQL. Postgres saknar
TRY_CAST, så base-vyernas och core-attributens konverteringar använder rakCASToch ett felformat värde ger fel vid laddning i stället för att bliNULL. På varje annat mål degraderar ett felaktigt värde tyst; på Postgres stoppar det laddningen. Profilering före den första core-laddningen är värd mer här än någon annanstans.
Hur källfiler läses
Varje motor når objektlagring på sitt eget sätt, och varje sätt har en förutsättning som måste finnas innan den genererade SQL:en körs. Generatorn skapar dem inte.
| Mål | Mekanism | Måste finnas i förväg |
|---|---|---|
| Snowflake | COPY INTO … FROM @<stage>/path | STORAGE INTEGRATION, STAGE, FILE FORMAT, WAREHOUSE; en EXTERNAL VOLUME för Iceberg-publicering |
| Databricks | read_files() mot en abfss://-URL eller en Unity Catalog-volym | STORAGE CREDENTIAL + EXTERNAL LOCATION med READ FILES tilldelat; ett SQL Warehouse eller DBR 13.3 LTS och senare |
| SQL Server / Synapse / Fabric | OPENROWSET(BULK …) med en formatfil | MASTER KEY, DATABASE SCOPED CREDENTIAL, EXTERNAL DATA SOURCE och formatfilen utrullad |
| PostgreSQL | En persistent pg_lake-främmandetabell per Published-tabell | PostgreSQL 15 eller senare, CREATE EXTENSION pg_lake CASCADE, molnbehörigheter konfigurerade för pg_lake, CREATE på Published-schemat |
Snowflake är det enda målet där behörigheter och bas-URL lever inuti databasen, i STAGE-objektet — ett databasobjekt hos Snowflake, som heter så oavsett vad PDQ kallar sina egna lager. Överallt annars bär den genererade SQL:en lagrings-URL:en och motorn löser åtkomsten separat.
Två beteenden är värda att känna till:
- Synapse Published-laddningar tillämpar inget filnamnsfilter. Varje annat mål avgränsar laddningen till den fil som bearbetas; på Synapse läser en Published-laddning in hela den upplösta sökvägen. Dimensionera sökvägen därefter och räkna med omläsningar.
- PostgreSQL läser radbrytningsseparerad JSON via en främmandetabell som skapas en gång, i Published-definitionen. Dess sökväg låses vid första skapandet, och publiceraren förutsätter att den definitionen skapat den — rulla därför ut Published-definitionen före publicering.
Orkestrering
| Mål | Schemaläggning inuti databasen | Beräkningsval | Satsstil |
|---|---|---|---|
| Snowflake | CREATE TASK, när generatorn körs för tasks | USE WAREHOUSE-prolog | Procedurell — EXECUTE IMMEDIATE … BEGIN … END |
| Databricks | Ingen — använd Workflows och Jobs | — | Sekventiella ;-separerade satser |
| SQL Server / Synapse / Fabric | Ingen — använd egen schemaläggare | — | Batchar separerade med GO;, DDL skyddad av IF NOT EXISTS |
| PostgreSQL | Ingen — använd egen schemaläggare | — | Sekventiella ;-separerade satser |
Snowflake är det enda målet som kan schemalägga sig självt. På varje annan plattform är det genererade skriptet en rak följd av satser, och något utanför databasen måste köra det — Databricks Workflows, Data Factory, Airflow eller DataOps-schemaläggaren.
Körtidsstämpeln följer samma uppdelning: en sessionsvariabel på Snowflake, en bindvariabel i T-SQL-familjen och en inline citerad literal på Databricks och PostgreSQL, som saknar procedurell variabel att binda mot.
Publiceringsformat
Publiceringsformaten som beskrivs på sidan DLS-lagret löses inte upp likadant överallt.
| Mål | TABLE | ICEBERG |
|---|---|---|
| Snowflake | Standardtabell | Nativ CREATE ICEBERG TABLE, kräver en EXTERNAL VOLUME |
| Databricks | Delta-tabell | Extern Delta-tabell med UniForm — Iceberg-metadata genereras parallellt och kan läsas av Snowflake, Trino med flera |
| PostgreSQL | Standardtabell | Faller tillbaka på en standardtabell |
| SQL Server / Synapse / Fabric | Standardtabell | Stöds inte — behåll formatet TABLE |
Om flermotorsåtkomst till publicerade data är ett krav är Snowflake och Databricks de två mål som levererar det.
Anteckningar per plattform
Snowflake
Referensimplementationen, och den mest kompletta. Allt generatorn kan generera, genererar den här: inline-kommentarer, nativa etiketter, maskeringspolicyer, Iceberg, tasks, sekvenser. Avvägningen är uppsättningen — STAGE, integration, filformat, warehouse och, för Iceberg, den externa volymen måste alla finnas och vara tilldelade före första körningen.
Databricks
Den starkaste katalogberättelsen och den svagaste villkorsberättelsen. Etiketter hamnar där Unity Catalog läser dem och kommentarer är inline, men ingenting upprätthålls: inget UNIQUE, inga fungerande primär- eller främmande nycklar, ingen mask på känsliga kolumner. Kvalitetskontroller är det enda sätt en överträdelse här över huvud taget blir synlig, så behandla dem som obligatoriska snarare än valfria — med i beräkningen att de rapporterar i efterhand snarare än förebygger. Två operativa detaljer: att ta bort en etikett går inte att köra om, eftersom Databricks ger fel om etiketten redan saknas; och DROP COLUMN kräver namnbaserad kolumnmappning i Delta, vilket generatorn aktiverar före borttagningen.
SQL Server
Det relationella referensmålet, och det som upprätthåller mest samtidigt som det bär minst metadata: unikhet är verklig, beskrivningar går till extended properties, främmande nycklar registreras men är inaktiverade. Published-tabellen trunkeras aldrig vid omladdning — ta höjd för det i gallring och i eventuell radantalsavstämning.
Azure Synapse
SQL Servers struktur med dedikerade poolers begränsningar ovanpå: inga främmande nycklar alls, NOT ENFORCED unika villkor, inga korsdatabasfrågor, inga beskrivningar i lagret och inget filnamnsfilter på Published-laddningar. Distributions- och indexval genereras inte — granska DDL:en och lägg till dem före produktionsbruk. Djupt nästlad JSON kan dessutom slå i OPENROWSET-radlängdsgränsen; se FAQ för lösningen.
Microsoft Fabric
T-SQL-familjen, där Fabric Warehouse-ytan är en rörlig delmängd av SQL Server. Unikhet upprätthålls, främmande nycklar är NOT ENFORCED, beskrivningar bärs inte in. Published-källans URL viker in trusted zone-segmentet i sökvägen, så trusted zone-inställningen måste stämma med din OneLake- eller container-layout. Eftersom Fabrics T-SQL-yta förändras bör genererad DDL granskas mot den aktuella ytan före en första produktionskörning.
PostgreSQL
Det enda målet som upprätthåller både unikhet och referentiell integritet, vilket gör det till den striktaste platsen att köra en modell på — och den där ett modelleringsfel visar sig som en misslyckad laddning i stället för som felaktiga data. Två ytterligare konsekvenser av den strikthet: identifierare genereras utan citattecken och viks till gemener, så ett modellobjekt uppkallat efter ett reserverat ord (Order, User) kommer att misslyckas; och typkonverteringar är strikta, så felformade värden ger fel i stället för NULL.
Att välja mål
| Om detta väger tyngst | Välj |
|---|---|
| Referentiell integritet garanterad av databasen | PostgreSQL |
| Styrningsmetadata som din katalog kan läsa | Snowflake eller Databricks |
| Dokumentation buren in i själva lagret | Snowflake eller Databricks |
| Flermotorsåtkomst till publicerade data | Snowflake, med nativ Iceberg, eller Databricks, med UniForm |
| Schemaläggning utan ytterligare orkestrerare | Snowflake |
| En befintlig Microsoft-miljö | SQL Server, eller Fabric för den nyare ytan |
Oavsett mål är luckorna kända i förväg, och var och en har ett planerat svar: kvalitetskontroller där villkor inte upprätthålls, konsoldokumentation där kommentarer inte bärs in, katalogpolicy där maskering inte genereras. Poängen med den här sidan är att svaret planeras snarare än improviseras.
Var dock exakt med vad en QPI-kontroll gör. En QPI-kontroll rapporterar. Den blockerar inte laddningen och hindrar inte felaktig data från att nå konsumenter — den gör avvikelsen synlig. Där ett mål inte upprätthåller ett villkor kan en dubblerad affärsnyckel skrivas, och en QPI-kontroll är hur du får veta det, inte hur du förhindrar det.
Nästa steg
- Vad som landar i målmiljön — vad det genererade schemat innehåller och var varje del kommer ifrån
- Datakvalitetskontroller — hur ett icke upprätthållet villkor blir synligt i efterhand
- DLS-lagret — publiceringsmönster och format · DWA-lagret — styrning på fältnivå
- Installation — att välja dataplattform för en installation
- Vad som ändras i 3.2 — releasen som lade till Databricks och PostgreSQL som mål