Parallel Data Warehouse: How MPP Query Engines Work
A team migrates a reporting query onto a parallel data warehouse with sixteen compute nodes and watches it run slower than it did on the single server they just left. Nobody has done anything obviously wrong. The hardware is real, the cluster is healthy, the query plan is not absurd. The problem is that one column was chosen as the distribution key eighteen months ago, that column has four distinct values, and so twelve of the sixteen nodes are sitting idle while four of them do all the work. Adding nodes made this worse, not better, because the cost of the cluster scaled and the work did not.
This is the central lesson of massively parallel processing, and the one vendor diagrams never show. An MPP engine does not make queries fast. It makes it possible for queries to be fast, provided the data has been physically arranged so the work can actually be divided. Get the layout wrong and you have bought a very expensive way to run a single-threaded query.
This guide covers the mechanics from the ground up: shared-nothing nodes, how a query gets split and reassembled, what distribution keys do, why data skew is so punishing, where Microsoft's SQL Server Parallel Data Warehouse and Analytics Platform System sit historically, and how cloud engines changed which decisions you still have to make. It ends with the question most people searching this term are really asking, which is whether they need one at all.
What a parallel data warehouse actually is
A parallel data warehouse is a database that stores one logical table as many physical pieces spread across independent machines, then answers a single SQL statement by running it simultaneously on every piece.
The architectural foundation is shared nothing architecture, a term that comes from Michael Stonebraker's 1986 paper of the same name. Each node in the cluster has its own CPU, its own memory, and its own storage. No node reads another node's disk. No node writes to another node's memory. The only thing nodes share is a network, and communication over that network is the expensive part that everything else is designed to avoid.
It helps to see the alternatives it was defined against:
- Shared memory (SMP). One machine, many cores, one pool of RAM. Simple and fast until you hit the biggest box you can buy or afford.
- Shared disk. Many machines, one storage array. Oracle RAC is the classic example. Coordination overhead grows because every node can touch every block and locking has to be negotiated cluster-wide.
- Shared nothing. Many machines, each owning its own slice. Coordination is minimal because ownership is unambiguous. Scaling out is close to linear, right up until the data is unevenly distributed and it stops being linear at all.
A massively parallel processing database picks shared nothing on purpose. The trade it accepts is that data placement becomes a design decision with permanent consequences, because a node can only work on the rows it physically holds.
The typical topology has a control node and a set of compute nodes. The control node holds metadata, parses incoming SQL, and produces a distributed plan. The compute nodes each hold a slice of the data, run local query fragments, and send results back for assembly. Other products call the control node a coordinator, leader, or head node, and the compute nodes workers or slices. The vocabulary changes, the shape does not.
How an MPP query engine splits one query into many
Take a simple statement: sum revenue by region for last quarter, joining an orders table to a customers table.
On a single server, the optimizer picks a scan method, a join method, and an aggregation method, and that is the plan. On an MPP data warehouse, the optimizer does all of that and then answers an extra question at every step: where do the rows need to be for this operation to be legal?
The distributed plan usually looks like this:
- Local scan. Each compute node scans only its own slice of the orders table and applies the date filter. This is the part that parallelizes beautifully. Sixteen nodes scan a sixteenth of the data each.
- Data movement, if required. The join needs matching customer rows and order rows on the same node. If they already are, nothing moves. If not, the engine shuffles: every node hashes the join key on its local rows and ships each row to whichever node owns that hash range. Microsoft's implementation handles this in a component literally named the Data Movement Service, with move types called shuffle move, broadcast move, and partition move.
- Local join and partial aggregation. Now that matching rows are colocated, each node joins and computes a partial sum for the regions it holds.
- Final aggregation. Partial sums travel back and get combined into one result set.
Steps 1, 3 and 4 are cheap and scale with node count. Step 2 is where queries go to die. A shuffle moves rows across the network, materializes intermediate results, and cannot complete until the slowest node finishes sending. A broadcast copies an entire table to every node, which is fine for a small lookup table and catastrophic for a large one.
Almost all real MPP tuning work reduces to a single objective: eliminate data movement, or make the data that has to move as small as possible.
Distribution keys, the decision that outlives everyone who made it
A distribution key, sometimes called a distribution column or a hash key, is the column whose value determines which node a row lives on. The engine hashes the value and maps the hash to a distribution. Same value, same node, always. That determinism is the whole point: if two tables are hashed on the same key, rows that need to be joined are guaranteed to already be sitting together, and the join runs with zero data movement.
Most MPP systems offer three placement strategies. Choosing between them per table is the core physical design job.
| Strategy | How rows are placed | Use it for | Failure mode |
|---|---|---|---|
| Hash distributed | Hash of one column decides the node | Large fact tables, tables joined on a stable key | Skew if the column has low cardinality or many nulls |
| Round robin | Rows dealt out evenly regardless of content | Staging and load tables, tables with no good key | Every join requires a shuffle, because placement is arbitrary |
| Replicated | Full copy of the table on every node | Small dimension tables such as region, product, currency | Writes multiply by node count, and large replicated tables blow up memory |
The rules for picking a hash column are unglamorous and rarely followed:
- High cardinality and even value frequency. Millions of distinct values, not five, and no single value dominating. A status or country column is a disaster as a distribution key, and so is customer id when one customer accounts for a third of your orders.
- Few nulls. Nulls all hash to the same value, so a nullable distribution column quietly funnels every null row onto one unfortunate node.
- Used in joins and group by. The whole benefit is colocation, so choose the column your heavy queries actually join on.
- Not used as an equality filter in most queries. This one is counterintuitive. If you distribute by date and almost every query filters to a single date, all the work lands on one node and the rest of the cluster idles.
- Stable. Updating a distribution key means deleting the row from one node and inserting it on another. Many engines simply forbid it.
The uncomfortable part is that these criteria conflict. The column your queries join on may be the column they filter on. The natural key may be badly skewed. Physical design in a massively parallel processing database is a negotiation, and the result gets baked into a table that will outlast the person who chose it.
Data skew, and why more nodes cannot rescue you
A distributed query is finished when its slowest fragment is finished. That single sentence explains almost every disappointing MPP benchmark.
If your data is perfectly even across sixteen nodes, each does 6.25 percent of the work and the wall clock is roughly a sixteenth of the single-node time, minus coordination overhead. If one node holds 40 percent of the rows, the wall clock is set by that node, and the other fifteen finish early and wait. Doubling to thirty-two nodes does not help, because the skewed node still holds the same oversized share of a badly hashed table. You have doubled the bill and changed nothing about the critical path.
Skew shows up in three distinct flavours, and they need different fixes:
Storage skew. Unequal row counts per distribution, caused by a poor hash column. Detectable by counting rows per distribution, which every MPP system exposes through a system view or dynamic management view. The fix is a redistribution to a better column, which means rewriting the table.
Processing skew. Row counts are even, but the work is not, because a filter or join predicate happens to concentrate on particular values. A table distributed by date with queries that always look at yesterday is the classic case. The fix is usually a different distribution column, occasionally a synthetic key.
Intermediate skew. The base tables are fine but a shuffle produces a lopsided intermediate result, typically because the join key itself is skewed. Fixes here get creative: splitting the heavy key out and unioning results, salting the key with a random suffix, or replicating the smaller side to avoid the shuffle entirely.
There is a related trap specific to columnstore engines. Columnstore compression groups rows into rowgroups of about a million rows. If a platform fixes the number of distributions at sixty, as Microsoft's dedicated SQL pool does regardless of how much compute you provision, then a table needs on the order of sixty million rows before every distribution can fill even one rowgroup. Below that, compression and scan performance are worse than they look on paper, and partitioning the table further makes it worse again. Small tables on big MPP clusters are not just unnecessary, they are actively penalized.
Where SQL Server Parallel Data Warehouse and Analytics Platform System fit
If you are searching this term because of a Microsoft product, here is the lineage, because the naming has changed roughly every three years.
Microsoft acquired DATAllegro in 2008 and used its technology to build SQL Server Parallel Data Warehouse, shipped as a rack-scale appliance starting with SQL Server 2008 R2. It was not software you installed. It arrived as pre-configured hardware from a partner such as HP or Dell, with a control node and compute nodes, each compute node running its own SQL Server instance over its own distributions.
In 2014, Microsoft rebranded the appliance as the Analytics Platform System. APS packaged the PDW engine as one region of the appliance and added an optional HDInsight region running Hadoop, with PolyBase as the bridge that let a single T-SQL query join relational tables to files in HDFS. That was ahead of its time. It is also the point where the appliance model started to look like the wrong shape, because buying a rack meant sizing your peak workload years in advance and paying for it continuously.
The engine survived the hardware. Azure SQL Data Warehouse launched in 2016 with the PDW query engine running as a cloud service, separating storage from compute so you could pause or resize the cluster. It was folded into Azure Synapse Analytics as the dedicated SQL pool, which is why Synapse still speaks PDW: distributions, hash distribution, replicated tables, DMS operations, and the fixed count of sixty distributions inherited straight from the appliance design. Microsoft Fabric's warehouse is the current step in that line, with physical distribution decisions increasingly handled by the platform rather than by you.
So when documentation, an old runbook, or a job description mentions PDW or APS, it usually points at one of three things: a genuinely legacy on-premises appliance, a Synapse dedicated SQL pool whose concepts and error messages descend from it, or an author using the older name out of habit.
MPP appliances, cloud MPP, and single-node engines compared
The last decade quietly moved the distribution problem around rather than solving it. Some engines still make you choose keys, some infer clustering automatically, and some do not shard at all because they do not need to.
| Approach | Examples | Do you choose distribution keys | Scaling model | Best fit |
|---|---|---|---|---|
| Classic MPP appliance | SQL Server PDW, Analytics Platform System, Teradata, Netezza | Yes, and permanently | Buy more rack | Legacy estates, on-premises mandates |
| Cloud MPP with explicit keys | Synapse dedicated SQL pool, Amazon Redshift | Yes, though both now offer automated advisors | Resize or pause provisioned compute | Very large, stable, join-heavy workloads |
| Elastic cloud warehouse | Snowflake, BigQuery, Databricks SQL | No, the platform clusters and shuffles for you | Per-query or per-warehouse, scales with usage | Most modern analytics teams |
| Single node columnar | DuckDB, ClickHouse on one machine, Postgres with columnar extensions | Not applicable | Buy a bigger machine | Datasets in the tens to hundreds of gigabytes |
The row that matters most here is the last one. A single modern server with a fast NVMe disk and a columnar engine will chew through datasets that would have required a rack of PDW hardware in 2012. Hardware got faster while a lot of company datasets stayed roughly the same size, so the threshold for needing massively parallel processing at all moved a long way up. Plenty of teams shop for MPP because the term sounds like the serious option, not because their data demands it.
Do you actually need a parallel data warehouse?
Be honest about which of these describe you.
Signals you genuinely need MPP. Tables in the hundreds of millions to billions of rows. Joins across several of those large tables at once. Dozens of concurrent analysts running unpredictable ad hoc SQL. Queries that already time out on the largest single machine available to you. A continuously busy workload, so provisioned compute is not sitting idle.
Signals you do not. Your largest table has a few million rows. Your reporting runs once a day and finishes in minutes. Your "data problem" is that numbers disagree between tools, not that queries are slow. Your team has no dedicated data engineer. Nobody can name the query that is currently too slow.
That last one deserves emphasis. A large share of warehouse projects begin without a single named query that is unacceptably slow today. They begin with a feeling that a real company should have a warehouse. That feeling costs a provisioned cluster billed by the hour whether or not anyone queries it, ingestion pipelines that break on schema changes, and a person whose job becomes keeping the whole thing coherent. Before committing, our guide to What Is a Data Pipeline? Stages, Tools, and Failure Modes walks through what feeding that machine involves, and Data Integration Tools: A Buyer's Guide for Lean Teams covers the connector layer that has to run reliably before any query engine matters.
There is a cheaper diagnostic worth running first. Take the three questions your leadership actually asks every week: which deals slipped, which customers went quiet, whether revenue is tracking. Check whether each answer needs a distributed scan of a billion rows, or data from four systems that have never been joined. Those are different problems, and only one is solved by parallel hardware. Our breakdown of SaaS Metrics That Matter: Definitions and How to Track is a reality check on how few of the metrics leadership cares about are actually compute-bound.
Where Skopx fits, and where it does not
Skopx is not a data warehouse, not a query engine, and not an ETL tool. It has no distributions, no distribution keys, no compute nodes, no MPP optimizer. If you have a genuine massively parallel processing problem, meaning billions of rows and joins that saturate a large server, nothing below replaces the engines described above. Buy the warehouse.
What Skopx addresses is the more common situation that sends people to this page: the questions are cross-system, not large. Revenue lives in Stripe, the pipeline in HubSpot or Salesforce, conversations in Gmail and Slack, tickets in a support tool, the books in QuickBooks. Nothing there is big. It is scattered, and no amount of parallelism fixes scattered.
Skopx connects nearly 1,000 tools a company already uses and answers questions in chat with cited data pulled from those connected systems. There is a morning brief, an insights engine that flags risks and anomalies, and workflows you build by describing them in chat rather than wiring a DAG. It runs on your own AI key for any major model with zero markup, at $5 per month for Solo and $16 per seat per month for Team, on the pricing page.
The boundaries are worth stating plainly. Skopx does not store years of immutable history, so reconstructing what a record looked like in March two years ago is a warehouse job. It does not build dashboards. It does not do heavy multi-table joins over hundreds of millions of rows. It is not a CRM. If your CRM data itself is inconsistent, that is an upstream problem to solve first, and Salesforce HubSpot Integration: Sync Fields Without Chaos is a better starting point than any query engine. If most of your operational context lives in a workspace tool, Notion Integrations: Connecting Notion to the Rest of Work covers that surface.
A representative workflow looks like this, and every step is an API call against a system you already pay for, not a distributed scan:
Weekly revenue and support check without a warehouse
Monday 8am
Scheduled trigger
Stripe
Pull last week's charges, refunds and failed payments
CRM
Pull deals that moved stage or went quiet
Support
Pull ticket volume by account
Analyse
Match accounts across the three sources and flag divergence
Post to Slack
Cited summary with links back to each source record
You can see how that style of automation is built on the workflows page. If your questions look like that one, a parallel data warehouse is the wrong purchase. If they genuinely involve scanning a billion rows, this is not the tool, and the earlier sections of this guide are the useful part of the page.
Frequently asked questions
What is the difference between a parallel data warehouse and a regular database?
A regular database runs a query in one process on one machine, even if that machine has many cores. A parallel data warehouse splits the same table across independent nodes, runs the query on all of them at once, and merges the results. The trade is that data placement becomes a permanent design decision: in a single-node database you add an index and move on, while in an MPP data warehouse a bad distribution key can require rebuilding the table.
How do I pick a distribution key?
Look for a column with high cardinality, an even spread of values, few or no nulls, frequent use in joins and group by clauses, and stability over time. Avoid columns you filter on with equality in most queries, because that concentrates work on one node. Then verify empirically: load a representative volume, count rows per distribution, and check that the spread is even before you build anything on top of it.
Are Redshift, Snowflake and BigQuery parallel data warehouses?
All three execute queries in parallel across many workers, so yes in the broad sense. They differ in how much of the physical layout you control. Redshift still exposes distribution and sort keys alongside automated table optimization. Snowflake manages micro-partitions and clustering for you. BigQuery gives you no distribution key and shuffles dynamically between execution stages. Fewer knobs means fewer catastrophic mistakes and less ability to hand-tune a pathological workload.
Is SQL Server Parallel Data Warehouse still supported?
The appliance line, PDW and later the Analytics Platform System, is legacy. Microsoft's current path runs through Azure Synapse Analytics dedicated SQL pools and Microsoft Fabric, both of which inherit the engine's concepts and much of its vocabulary. If you are running an appliance today, the migration target is a cloud pool or a Fabric warehouse, and the distribution design you already have will largely carry over.
How big does my data need to be before MPP makes sense?
There is no universal number, but a practical test beats any threshold: try the workload on one large machine with a modern columnar engine first. If a single well-provisioned server running DuckDB, ClickHouse, or a columnar Postgres setup answers your queries in acceptable time, you do not need a cluster. Most teams under a few hundred gigabytes with modest concurrency are comfortably in single-node territory, which means no skew, no shuffles, and no distribution keys to get wrong.
We have slow reports but small data. What is the real problem?
Usually one of three things: a report joining data pulled on different schedules, so it waits on the slowest extract; a modelling problem where the same metric is defined differently in different places; or a visualization layer that re-queries the source on every interaction. Parallelism solves none of those. Fixing the pipeline, the definitions, or the caching will get you further than any cluster, and far more cheaply.
Skopx Team
The Skopx engineering and product team