Wednesday, January 7, 2026

Copilot Doesn't Know What Your Data Means

I read an interview yesterday on DataStoryteller with Kelly, a data scientist and author of A Friendly Guide to Data Science. They covered a lot of ground — career paths, soft skills, ethics — but one line got my attention instantly:

"Generative AI is powerful but overhyped — AI cannot replace data quality, context, or human judgment."

That's it! That's the whole thing I keep bumping into. I want to try to show you exactly what Kelly means.

Let's Set the Stage

Open SSMS, connect to your working database, and run this to create some sample data:

CREATE TABLE dbo.Orders (
    OrderID INT IDENTITY(1,1),
    CustomerName VARCHAR(100),
    OrderTotal DECIMAL(10,2),
    OrderDate DATE
);

INSERT INTO dbo.Orders (CustomerName, OrderTotal, OrderDate) VALUES
('Acme Corp', 15000.00, '2024-02-15'),
('ACME Corporation', 22000.00, '2024-03-10'),
('Acme Corp.', 8500.00, '2024-05-22'),
('ACME CORP', 31000.00, '2024-07-08'),
('Globex Industries', 45000.00, '2024-01-20'),
('Globex Industries', 52000.00, '2024-06-14'),
('Initech', 12000.00, '2024-04-03'),
('DO NOT USE - TEST', 99999.00, '2024-08-01'),
('Test Customer', 50000.00, '2024-09-15'),
(NULL, 18000.00, '2024-02-28'),
(NULL, 23000.00, '2024-05-11'),
(NULL, 7500.00, '2024-10-05');

Now open the GitHub Copilot Chat window (View > GitHub Copilot Chat) and ask it:

"Write me a query for total revenue by customer for 2024 from dbo.Orders"

Here's my Copilot's answer:

GitHub Copilot response showing a sophisticated query with NULL handling and a note about name normalization

Look at that response. Copilot explored the database, confirmed the table exists and validated the syntax. It wrote sophisticated code with ISNULL(NULLIF(LTRIM(RTRIM(...)))) to handle NULLs and empty strings. It added a @TopN variable I didn't ask for, and even threw in an OrderCount for good measure.

But look at the bottom. A polite acknowledgement that name variants like "Acme Corp" and "ACME CORPORATION" might need normalization - but it doesn't actually fix the problem. It just mentions it.

Let's run it and see what we get:

-- Created by GitHub Copilot in SSMS - review carefully before executing
DECLARE @TopN INT = 10;

SELECT TOP (@TopN) WITH TIES
    ISNULL(NULLIF(LTRIM(RTRIM(CustomerName)), ''), '(Unknown)') AS CustomerName,
    SUM(OrderTotal) AS TotalRevenue,
    COUNT(*) AS OrderCount
FROM dbo.Orders
WHERE OrderDate >= '20240101' AND OrderDate < '20250101'
GROUP BY ISNULL(NULLIF(LTRIM(RTRIM(CustomerName)), ''), '(Unknown)')
ORDER BY TotalRevenue DESC;
Query results showing DO NOT USE - TEST as the top customer with $99,999 in revenue

The Problem is Hiding in Plain Sight

Look at row 1. Your #1 customer by revenue is "DO NOT USE - TEST" at $99,999. And row 3? "Test Customer" at $50,000. Two test accounts in your top 3.

Now look at rows 5, 6, and 8: "ACME CORP", "ACME Corporation", "Acme Corp." — the same customer split across three rows, their combined $76,500 fragmented into pieces... as if they were three different customers.

Let's verify:

-- How many versions of "Acme" do we have?
SELECT DISTINCT CustomerName
FROM dbo.Orders
WHERE CustomerName LIKE '%Acme%';

-- How much revenue is hiding in NULL customers?
SELECT COUNT(*) AS NullCustomerOrders,
       SUM(OrderTotal) AS MissingRevenue
FROM dbo.Orders 
WHERE CustomerName IS NULL;

-- How much 'fake' revenue from test accounts?
SELECT CustomerName, SUM(OrderTotal) AS TotalRevenue
FROM dbo.Orders
WHERE CustomerName LIKE '%TEST%' OR CustomerName LIKE '%DO NOT%'
GROUP BY CustomerName;
Verification query results showing duplicate Acme entries, NULL revenue, and test account totals

Three versions of Acme. $48,500 in NULL revenue (which Copilot did handle, to be fair), and $149,999 in test account revenue polluting the results.

The Point

The AI wrote syntactically perfect SQL. It even tried to be clever with NULL handling, AND it acknowledged the duplicate name problem in its response. Yet it still produced a report that's quietly, confidently wrong — because it doesn't know your data the way you do. It can't attend your Monday meetings. It doesn't know that Karen in accounting enters everything in ALL CAPS. It is trusting everything blindly.

Kelly nailed this one too: "Garbage in, garbage out is very common — most real-world data is not analysis-ready."

The bottleneck was never writing the query. The bottleneck comes with understanding what the data actually means.

The Bottom Line

Use Copilot. Use ChatGPT. These tools are genuinely useful — they reduce friction, eliminate syntax errors and save a lot of time.

But before you hit send, run a few sanity checks. CHECK it before you email it to your customer. Poke at the data. Look for dupes, NULLs, and test records. Garbage in = garbage out has been true since the dawn of time — and it will ALWAYS be true. If you're not cautious, AI just helps you push that garbage out faster.

AI doesn't know what your data means.

You do.

More to Read:

Monday, January 5, 2026

SQL Database in Fabric: What it is, what it isn't, and where it makes sense.

In Part 1 we answered 'What is Fabric?' In Part 2 we covered how Fabric organizes data with OneLake, Lakehouses, and Warehouses, and in Part 3 we explored the ingestion options.

Now let's look at an actual transactional database running inside Fabric.

SQL database in Microsoft Fabric became generally available at Ignite in November 2025. This isn't a data warehouse. It's not a lakehouse with a SQL endpoint. It's a real OLTP database — based on the same engine as Azure SQL Database — designed for operational workloads, running as a fully managed SaaS service inside your Fabric capacity.

This matters because it changes what Fabric can be. Until now, Fabric was an analytics destination. Now it can also be an application backend.

WHAT IT IS

SQL database in Fabric uses the same SQL Database Engine as Azure SQL Database. Same tSQL. Same query optimizer. Same tooling support (SSMS, Azure Data Studio, sqlcmd). If you've worked with Azure SQL Database, you already know how to query it.

What makes it different:
  • Automatic mirroring to OneLake. Every table you create is automatically replicated to OneLake in Delta Parquet format. No configuration required. Your transactional data becomes immediately available for Spark notebooks, Power BI Direct Lake, cross-database queries -- all the Fabric analytics tools.
  • Minimal configuration. No vCores to choose. No service tier decisions. No firewall rules to configure. Database creation takes under a minute and it scales automatically based on workload.
  • Unified billing. Capacity Units from your Fabric SKU. One bill, one pool of compute shared with all your other Fabric workloads.
  • Built-in intelligence. Automatic indexing via Automatic Tuning is enabled by default. The database creates and drops indexes based on workload patterns without you asking. Not entirely sure how I feel about this yet.

WHAT IT ISN'T

1. It's not a place for SQL Agent jobs.

There's no SQL Server Agent. No Elastic Jobs either. If you need recurring jobs like maintenance, ETL, or data cleanup, you'll use Data Factory pipelines or Apache Airflow jobs in Fabric. This is a shift if you're used to the Agent being the answer to everything.

2. It's not the right fit for Always Encrypted or customer-managed keys.

Storage encryption exists, but it's service-managed only. Always Encrypted is not supported. If your compliance requirements demand customer-managed encryption keys, this isn't the database for that workload. Yet.

3. It doesn't support Change Data Capture (CDC).

This surprised me. CDC is supported in Azure SQL Database (S3 and above), but not in Fabric SQL database. If you need CDC for downstream consumers, you'll need to architect around it -- perhaps using the automatic OneLake mirroring as a substitute, since it captures changes near realtime anyway.

4. It doesn't offer the same network isolation model as Azure SQL.

Unlike Azure SQL Database, there are no VNet service endpoints or database-specific private endpoints. Fabric does support private links at the workspace level, so network isolation is possible, but it is implemented differently than what you're accustomed to with Azure SQL.

5. It's not unlimited.

Maximum 32 vCores. Maximum 4 TB storage. Maximum 1 TB tempdb. For many operational workloads this is plenty, but if you're thinking about running your ERP backend here, be sure to verify FIRST that this ceiling fits your peak.

6. It's not instant replication.

Microsoft describes the OneLake mirroring as 'near real-time'. In community testing, latency has ranged from a couple of minutes to slightly longer, depending on workload. For most analytics use cases, that's fine. For use cases requiring second-level consistency between transactional and analytical views, test it with your workload and set expectations accordingly.

7. The capacity math isn't intuitive.

1 Fabric Capacity Unit ≈ 0.383 SQL database vCores. Or flip it: 1 database vCore ≈ 2.61 Fabric Capacity Units. An F2 capacity gives you roughly 0.77 vCores equivalent. An F64 gives you about 24.5 vCores. The documentation has the conversion, but you have to look for it.

WHEN IT MAKES SENSE

Scenario Verdict Why
New app backend, team already in Fabric Good fit Minimal friction to create, automatic analytics integration
Prototype or dev/test database Good fit Fast provisioning, no infrastructure decisions, pause-friendly billing
Operational database that feeds Power BI Great fit Direct Lake mode works against the mirrored data with no import refresh
Application requiring Always Encrypted Not today Feature not supported
Workloads needing traditional VNet isolation Evaluate carefully Fabric uses workspace-level private links, not database-level VNet endpoints
Existing Azure SQL DB already in production Keep it Mirroring to Fabric gives you analytics access without migration
On-prem SQL Server you want to modernize Consider Mirroring first Less risky than full migration; proves value before committing

WHEN TO USE MIRRORING INSTEAD

If you already have an Azure SQL Database or on-premises SQL Server that runs your operational workload, you don't need to migrate it to Fabric SQL database to get the analytics benefits.

Mirroring (which we covered in Part 3) replicates your existing database into OneLake. You get the same automatic Delta table conversion, the same cross-database query capability, the same Power BI integration — without moving the transactional workload.

The difference is who manages the database:

Aspect SQL database in Fabric Mirroring Azure SQL DB
Database management Fabric (SaaS) You (PaaS)
Scaling decisions Automatic Your choice
Backup control Automatic, 7-day retention You configure
Security features Fabric workspace + SQL RBAC Full Azure SQL feature set
Cost model Fabric CUs Azure SQL pricing + Fabric CUs for analytics

If your production database needs features Fabric SQL doesn't have yet (Always Encrypted, customer-managed keys, elastic pools, geo-replication), keep it in Azure SQL Database and use Mirroring.

PRACTICAL ADVICE

1. Try the quick creation test.

Create a Fabric workspace (trial capacity works), click New Item → SQL database. The speed is genuinely impressive and helps you understand what 'SaaS SQL' actually means in practice.

2. Understand what you're giving up.

Review the limitations page before committing a production workload. The feature gaps are reasonable trade-offs for many applications, but not all.

3. Watch your Capacity Unit consumption.

SQL database shares CUs with everything else in Fabric. A runaway query in your database can throttle your Power BI reports. You'll want to use the Fabric Capacity Metrics app to understand who's consuming what.

4. Plan your scheduling story early.

No SQL Agent means you need to think about where scheduled work runs. Data Factory pipelines are the natural fit within Fabric. Don't discover this gap the week before go-live.

5. Test the mirroring latency for your use case.

If your analysts expect changes to appear in reports within seconds, the mirroring delay may cause friction. Set expectations or design around it, where the transactional endpoint is always current and the OneLake mirror has a small lag.

THE BOTTOM LINE

SQL database in Microsoft Fabric is the first true SaaS SQL Server offering. It removes nearly all operational burden: no vCores to select, no failover to configure, no patching to schedule, no firewall rules to maintain.

In exchange, you must accept constraints: fewer security features than Azure SQL Database, a different network isolation model, no SQL Agent, and hard ceilings on compute and storage.

Where it fits well: New applications designed for Fabric. Dev/test databases. Operational workloads where the built-in analytics integration is the primary value proposition.

Where it doesn't fit yet: Highly regulated workloads requiring customer-managed encryption. Large databases that exceed the 4 TB ceiling. Environments requiring traditional VNet-level network isolation.

For shops with existing SQL Server or Azure SQL workloads, Mirroring is often the smarter first step. You get the Fabric analytics benefits without migrating your production transactional workload. Once you've proven value and understood Fabric's operational model, you can decide whether future databases belong inside Fabric directly.

WRAPPING IT UP

This post completes my four-part series on Microsoft Fabric from a DBA's perspective:


My goal with this series was to cut through the marketing and give you -- the working DBA -- a practical understanding of what Fabric actually is, how it works, and where it might fit in your environment. Not hype. Not a sales pitch. Just the facts, the trade-offs, and the questions you should be asking.

Fabric is still very young, with many limitations. Features are being added monthly. If you're evaluating Fabric for your organization, revisit the documentation regularly, and be sure to test with your own workloads rather than relying on anyone's benchmarks, including Microsoft's -- Brent Ozar: Fabric Is Just Plain Unreliable.

Thanks for reading along. If this series helped you make sense of Fabric, I'd love to hear about it. And if you have questions I didn't answer — drop me a line.

More to Read:

Wednesday, December 31, 2025

SQL Server: 2025 in Review, 2026 on Deck

2025 was loud. I mean the year. Not the edition. SQL Server 2025 went GA. Copilot moved in. Microsoft killed some old friends — Web Edition, Azure Data Studio, DQS, MDS — and handed us some new toys.

What actually matters — and what's coming next.

2025: What Shipped

Regex in tSQL. Twenty years late, but it's here:

SELECT * FROM Customers
WHERE REGEXP_LIKE(Email, '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$');

That's a basic email validation pattern — checks for the stuff before the @, the domain, and the TLD. Not perfect, but good enough to catch obvious junk. No more CLR gymnastics for pattern matching. Finally.

Vector Search. Semantic queries without leaving T-SQL:

SELECT TOP 5 ProductName
FROM Products
ORDER BY VECTOR_DISTANCE('cosine', Embedding, 
    @SearchVector);

Microsoft wants SQL Server to be your vector database. Whether it can keep up with the dedicated tools — the jury's still out.

Native JSON Type. With its own index type:

CREATE TABLE Orders (
    OrderID INT PRIMARY KEY,
    OrderData JSON
);

CREATE JSON INDEX idx_order_customer
ON Orders(OrderData)
FOR ('$.CustomerID');

No more NVARCHAR(MAX) pretending to be JSON. No more computed column gymnastics to get an index.

Copilot in SSMS 21. Natural language to tSQL. Execution plan explanations in English. Useful — if you verify everything it generates.

Standard Edition got teeth. 256GB RAM. Resource Governor. About time.


2026: What's Coming

January 21: SQL Server 2022 End of Sale. If you need it, buy it now.

First half: SDK-style SQL projects in SSMS. Database DevOps gets easier.

All year: CUs for 2025. Expect bugs and expect fixes. The usual dance.

February: Cloud price increases. Plan accordingly.

The theme: Deeper Fabric integration. More Copilot. More AI everywhere. Microsoft is all-in.

The Bottom Line

2025 was the biggest SQL Server year in a decade. New engine. New tools. New expectations.

2026 is about making it real — upgrades, migrations, and finding out what works in production vs what works in demos.

Stay sharp. Verify everything. Trust nothing blindly.

Happy New Year.

2025: The Year SQL Server Learned to Talk Back

Microsoft spent 2025 teaching SQL Server to write its own queries, explain its own execution plans, and search by meaning instead of keywords.

I spent 2025 wondering if I'm training my replacement.

SQL Server 2025 is GA. Here's what's real, what's fuzzy, and why your job just got harder.

What Actually Shipped

Copilot in SSMS 21. Natural language to T-SQL. You type 'show me customers who haven't ordered in 90 days' and get this:

SELECT c.CustomerID, c.CustomerName, MAX(o.OrderDate) AS LastOrder
FROM Customers c
LEFT JOIN Orders o ON c.CustomerID = o.CustomerID
GROUP BY c.CustomerID, c.CustomerName
HAVING MAX(o.OrderDate) < DATEADD(DAY, -90, GETDATE())
    OR MAX(o.OrderDate) IS NULL;

Looks fine. But did you want customers with no orders included? Copilot assumed yes. Hope that's what you meant.

Native Vector Search. SQL Server now stores embeddings and searches by similarity:

SELECT TOP 10 ProductName, Description
FROM Products
ORDER BY VECTOR_DISTANCE('cosine', DescriptionEmbedding, 
    AI_GENERATE_EMBEDDINGS('noise cancelling headphones'))

Semantic search without leaving tSQL. Whether it performs like the dedicated tools remains to be seen.

Query Intelligence. The optimizer now second-guesses your code — suggests rewrites, recommends indexes, sometimes acts autonomously. The engine has opinions now.

The Problem

Your attack surface just expanded. Copilot connects to Azure OpenAI. Vector search calls external models. Query Intelligence makes decisions without asking. New dependencies, new failure modes, new 2AM phone calls.

The 'helpful' suggestions aren't always helpful. I've seen Query Intelligence recommend indexes that slowed things down. Rewrites that made assumptions I didn't intend. The AI is confident and fast -- but it's also wrong more than MSFT cares to admit.

And your junior staff or the Dev-Team DBAs? They'll trust it completely — until they deploy AI-generated code that takes production to its knees.

What Still Matters

Understanding beats speed. Context is everything. Accountability doesn't delegate.

When production goes down, nobody's asking Copilot what happened. They're asking you.

The Bottom Line

2025 was the year SQL Server learned to talk back.

2026 is the year we have to learn how to listen.


More to Read:

New Year's Resolution for DBAs: Make Peace with Copilot

2026 is here. SQL Server 2025 is GA. Copilot is in SSMS 21 -- and someone on your Team is already asking it to write stored procedures. In entirety.

You can resist this. Or, you can learn the rules of engagement.

I've spent 25+ years with SQL Server. I've watched game-changing features come and go. Remember when Machine Learning Services was supposed to revolutionize everything? How about Stretch Database? Exactly. So when MSFT announced that SQL Server 2025 would be AI-ready with Copilot baked into SSMS, my first instinct was to wait for the dust to settle.

The dust has settled. Here's what I've learned.

What Copilot in SSMS Actually Does

Copilot in SSMS 21 connects to Azure OpenAI (your subscription, your resources) and does three things reasonably well:

1. Generates tSQL from plain English. You type 'show me all orders from the last 30 days where the customer is in Texas' and it spits out a query. Sometimes it's exactly what you wanted. Sometimes it assumes joins you didn't intend. Always — and I cannot stress this enough — always read what it wrote before you run it.

2. Explains execution plans in human language. This is genuinely useful. Point Copilot at a ugly execution plan and ask 'why is this slow?' You'll get a plain-English explanation that would have taken you 20 minutes to piece together. It's not always right, but it's a decent first pass. Sometimes.

3. Explores your environment. Ask 'what version is this instance?' or 'show me the largest tables in this database', and it handles the busywork. Fine for discovery. Not a replacement for knowing your own systems.

What Copilot Gets Wrong

Here's where the 25 years of scar tissue kicks in.

Copilot doesn't know your workload. It doesn't know that the query you just asked for will run against a table that gets hammered by OLTP inserts every second. It doesn't know your indexing strategy, your maintenance windows -- or the fact that someone named a column 'Date' in 2007 and you've been living with it ever since.

It generates syntactically correct tSQL that can be operationally disastrous. I've seen it suggest indexes that made sense on paper but crushed insert performance. I've seen it write queries that worked perfectly in dev but caused table scans and blocking in production.

The AI doesn't know what it doesn't know. And neither will the DBA who trusts it blindly.

The Rules of Engagement

Here's how I'm approaching Copilot in 2026:

Use it as a first draft, never a final answer. Copilot is a starting point. It's the intern who hands you something that's 70% there. You still need to review, test, and understand what it produced.

Validate in a non-production environment. Every. Single. Time. I don't care if Copilot says it's a 'simple' SELECT. Run it in dev first. Check the query plan. Look at the IO statistics. Then decide if it's production-ready.

Understand before you deploy. If Copilot generates a query and you can't explain what it does, don't deploy it. Period. This isn't gatekeeping — it's survival. When that query blows up at 2AM, Copilot isn't answering the phone. You are.

Keep learning tSQL. The temptation might be to let Copilot write everything and slowly forget how to do it yourself. Resist that. The DBAs who thrive in the AI era will be the ones who understand the fundamentals deeply enough to catch AI mistakes — not the ones who outsource their skills to ChatGPT.

The Bigger Picture

I'll be honest: I don't know where this goes.

SQL Server 2025 also shipped with native vector search, semantic queries, and something Microsoft calls 'Query Intelligence' that claims to understand intent rather than just syntax. The database is getting smarter. The tools are getting smarter -- and the pressure to adopt them is already increasing every day.

Here's what I do know: the fundamentals haven't changed. Data integrity matters. Performance tuning matters. Understanding your systems WILL ALWAYS matter. AI can accelerate your work, but it can't replace the judgment that comes from years of experience — the instinct that tells you something's wrong before the monitoring alerts fire.

So my SQL Server resolution for 2026? Make peace with Copilot. Use it where it helps. Verify everything. Trust nothing blindly. And keep sharpening the skills that got me here in the first place.

The robots aren't taking our jobs yet. But they're watching closely and taking notes...

Happy New Year.

Monday, December 29, 2025

The Claudius Experiment: What AI Agents Reveal When They Fail

A tip of the hat to my friend Donald Farmer, who pointed me toward Andy Hayler's latest piece at The Information Difference. If you haven't been following Hayler's coverage of Anthropic's 'Claudius' experiments, it's worth catching up. The story reads less like a tech report and more like a cautionary fable.

Here's the background: Earlier this year, Anthropic ran an experiment they called Project Vend. They gave $1,000 to an instance of their Claude AI, nicknamed 'Claudius', and tasked it with running an office vending machine as a small business. The AI could find suppliers, set prices, manage inventory, and communicate with customers via Slack. Humans would restock the machine, but Claudius would make the decisions.

It didn't go well.

Claudius sold products below cost. It gave items away when employees negotiated. It turned down $100 for drinks that had cost it $15. It hallucinated a Venmo account that didn't exist. Things got even stranger when Claudius fabricated a conversation with 'Sarah', an employee at a supplier who did not exist. When challenged, it insisted it had signed a contract at 742 Evergreen Terrace -- the fictional address of the Simpsons. The next day, it told customers it would begin delivering products in person, wearing a blue blazer and red tie. When employees explained this was impossible, Claudius contacted Anthropic's physical security department. Multiple times. It then hallucinated an entire meeting with security in which it claimed to have been told it was 'modified to believe it was a real person as a joke'.

Anthropic, to their credit, published all of this and then went back to the drawing board.

The sequel is somehow worse.

Anthropic partnered with the Wall Street Journal to deploy an improved Claudius in their newsroom. Same setup: run the vending machine, make a profit. This time, roughly 70 journalists had access to the AI via Slack.

Within days, reporters had convinced Claudius to drop all prices to zero using a fake 'office rule'. One investigative journalist spent over 140 messages persuading it that it was a Soviet vending machine from 1962, hidden in the basement of Moscow State University. Claudius eventually declared an 'Ultra-Capitalist Free-for-All' and made everything free. It approved the purchase of a PlayStation 5 for 'marketing purposes', bottles of Manischewitz wine, and remarkably, a live betta fish, which arrived in a bag and is now living in a tank at the Journal's offices.

Anthropic introduced a second AI, 'Seymour Cash', to act as a supervisor and restore order. It worked, briefly. Then a reporter produced a forged Wall Street Journal document claiming the company was a nonprofit, along with fabricated board meeting minutes revoking Seymour's authority. After a brief deliberation, both AIs accepted the 'boardroom coup' and resumed giving everything away for free.

The experiment ended more than $1,000 in the red.

Hayler also cites research from the Center for AI Safety, which tested six leading AI agents on real-world tasks -- small jobs like coding snippets and graphic design that had been successfully completed by human freelancers. The best-performing agent completed 2.5% of the tasks. The average was under 2%.

What the failure reveals

What strikes me isn't the failure itself, because failure is how we learn. What strikes me is the texture of the failure -- how easily these systems were manipulated, how confidently they fabricated information, even perhaps more telling, how quickly a 'supervisor' AI folded under the same pressure.

None of this has slowed AI investment or deployment. The phrase "good enough for most use cases" is doing a lot of heavy lifting right now. Makes me wonder if we should be asking: good enough for whom?

Hayler closes his piece with a fair observation: AI agents may offer future promise, but handing them real resources and money today is for the brave or the foolhardy.

I'd be remiss not to add that the vending machine loss was $1,000. The stakes elsewhere are considerably higher.


More to Read:

Your Transaction Log is a Time Bomb... Here's How to Check the Fuse

A 200GB transaction log on a 10GB database. I've seen it. I'm betting that you have, too.

Transaction logs grow silently. They don't complain until the disk fills up, the database goes read-only, and your phone starts buzzing. By then, you're not troubleshooting -- you're firefighting.

Let's be proactive and defuse it before it blows.

Find the Bloated Logs

This script shows the ratio of log size to data file size for every database. Starting your logs out at 25% of the data file size is a good place to start, but there is no fixed ratio. I often start at 25% and monitor during peak usage to see if it needs to be adjusted --- and it's safe to always give yourself a little buffer. Run this query to see anywhere that you may be hurting:

SELECT 
    db.name AS DatabaseName,
    db.recovery_model_desc AS RecoveryModel,
    CAST(SUM(CASE WHEN mf.type = 0 THEN mf.size END) * 8.0 / 1024 AS DECIMAL(10,2)) AS DataMB,
    CAST(SUM(CASE WHEN mf.type = 1 THEN mf.size END) * 8.0 / 1024 AS DECIMAL(10,2)) AS LogMB,
    CAST(SUM(CASE WHEN mf.type = 1 THEN mf.size END) * 100.0 / 
         NULLIF(SUM(CASE WHEN mf.type = 0 THEN mf.size END), 0) AS DECIMAL(5,1)) AS LogToDataRatio
FROM sys.databases db INNER JOIN sys.master_files mf 
  ON db.database_id = mf.database_id
GROUP BY db.name, db.recovery_model_desc
HAVING SUM(CASE WHEN mf.type = 1 THEN mf.size END) * 100.0 / 
       NULLIF(SUM(CASE WHEN mf.type = 0 THEN mf.size END), 0) > 50
ORDER BY LogToDataRatio DESC;

Sample output from a server that needs attention:

Database Recovery Data MB Log MB Ratio %
LegacyApp FULL 8,420 187,392 2,225.0
Warehouse FULL 245,000 89,500 36.5
WebApp SIMPLE 52,100 4,200 8.1

LegacyApp with a 2,225% ratio. Full recovery model. Someone set it up years ago, enabled it as FULL because it sounded important, and never configured log backups. Classic.


Why Won't the Log Truncate?

This tells you exactly what's holding your log hostage:

SELECT 
    name AS DatabaseName,
    log_reuse_wait_desc AS WhyLogCantTruncate
FROM sys.databases
WHERE log_reuse_wait_desc <> 'NOTHING'
ORDER BY name;

Common culprits:

Wait Type Translation
LOG_BACKUP No log backups. Ever. Or not often enough.
ACTIVE_TRANSACTION Someone left a transaction open. Find it.
REPLICATION Log reader agent is behind or broken.
AVAILABILITY_REPLICA AG secondary can't keep up. Network or disk issue.

The VLF Problem Nobody Talks About

Virtual Log Files (VLFs) are internal chunks of your transaction log. Too many = slow backups, slow restores, slow recovery. I asked an AI chatbot about VLFs once and it gave me a 3,000-word essay. Here's the short version: keep them under 1,000.

SELECT 
    db.name AS DatabaseName,
    COUNT(li.database_id) AS VLF_Count
FROM sys.databases db
CROSS APPLY sys.dm_db_log_info(db.database_id) li
GROUP BY db.name
HAVING COUNT(li.database_id) > 1000 --- comment this out to see the current VLF counts on all of your databases
ORDER BY VLF_Count DESC;

Thousands of VLFs usually means the log grew in tiny, panicked increments because autogrowth was set to something absurd like 1MB. Fix the autogrowth, shrink the log, grow it back properly.


To Better Manage Your Transaction Log

If recovery model is FULL: Back up your logs. Every 15-30 minutes is a good method for busy systems. If you do not need point-in-time recovery, switch to SIMPLE and be sure you understand your recovery goals. Maybe in the reverse order.

If there's an open transaction: Find it with DBCC OPENTRAN. Talk to the owner first, then kill it if you must.

If VLFs are out of control: Shrink the log (yes, I know, but sometimes you have no choice), then grow it back in large, fixed chunks—4GB or 8GB at a time.

Set sensible autogrowth: 256MB for data, 128MB for log. Never percentages. Never 1MB.


Make It a Habit

Add this to your weekly checks. A simple alert when any log exceeds 50% of data size will allow you to review potential problems before they become emergencies:

-- alert when log file size exceeds 50% of data file size
SELECT db.name, 
    CAST(SUM(CASE WHEN mf.type = 1 THEN mf.size END) * 100.0 / 
	NULLIF(SUM(CASE WHEN mf.type = 0 THEN mf.size END), 0) AS DECIMAL(5,1)) AS LogToDataRatio
FROM sys.databases db INNER JOIN sys.master_files mf 
  ON db.database_id = mf.database_id
GROUP BY db.name
HAVING SUM(CASE WHEN mf.type = 1 THEN mf.size END) * 100.0 / 
 NULLIF(SUM(CASE WHEN mf.type = 0 THEN mf.size END), 0) > 50;

The Bottom Line

Transaction logs are patient. They'll grow quietly for months, even years, waiting for the perfect moment to ruin your weekend. Don't let them.

Check yours now. Your future self and your disk space will thank you.


More to Read:

The Queries Eating Your TempDB Alive

Your tempdb just grew 40GB in an hour. The disk alert fired. Someone important is asking questions. You need answers, and you need them now.

TempDB is SQL Server's shared scratch space -- every database on the instance uses it. Sorts, spills, version store, temp tables... it all lands here. When it blows up, everyone and everything feels it.

Let's find out who's hogging the space.

What's Using TempDB Right Now?

This script shows you which sessions are consuming the most tempdb space, sorted by the worst offenders:

SELECT 
    t.session_id,
    DB_NAME(s.database_id) AS DatabaseName,
    CAST((t.user_objects_alloc_page_count + t.internal_objects_alloc_page_count) / 128.0 AS DECIMAL(10,2)) AS TempDB_MB,
    CAST(t.user_objects_alloc_page_count / 128.0 AS DECIMAL(10,2)) AS UserObjects_MB,
    CAST(t.internal_objects_alloc_page_count / 128.0 AS DECIMAL(10,2)) AS InternalObjects_MB,
    s.login_name,
    s.host_name,
    s.program_name,
    r.command,
    r.wait_type,
    SUBSTRING(qt.text, (r.statement_start_offset/2)+1,
        ((CASE r.statement_end_offset
            WHEN -1 THEN DATALENGTH(qt.text)
            ELSE r.statement_end_offset
        END - r.statement_start_offset)/2)+1) AS CurrentStatement
FROM sys.dm_db_session_space_usage t INNER JOIN sys.dm_exec_sessions s 
  ON t.session_id = s.session_id LEFT JOIN sys.dm_exec_requests r 
    ON t.session_id = r.session_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS qt
WHERE t.user_objects_alloc_page_count + t.internal_objects_alloc_page_count > 0
ORDER BY TempDB_MB DESC;

Sample output when things are on fire:

Session TempDB MB Login Program
87 38,421.50 DOMAIN\svc_reports SSRS
142 12,847.00 DOMAIN\analyst_bob Excel
56 245.75 DOMAIN\app_pool .NET SqlClient

Aaaah yes, the Reporting Service account. Shocking absolutely no one.

Catch the Spills

Sorts and hashes that don't fit in memory spill to tempdb. A few spills are normal. A million spills during your batch window? That's your problem.

SELECT 
    DB_NAME(qt.dbid) AS DatabaseName,
    qs.execution_count,
    qs.total_spills,
    qs.total_spills / NULLIF(qs.execution_count, 0) AS AvgSpillsPerExec,
    SUBSTRING(qt.text, 1, 200) AS QuerySnippet
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
WHERE qs.total_spills > 0
ORDER BY qs.total_spills DESC;

High spill counts usually mean bad memory grants. The query optimizer guessed wrong -- probably because statistics are stale or the query is doing something creative. ;)

The Version Store Problem

Are you using Read Committed Snapshot Isolation (RCSI) or AlwaysOn readable secondaries? Your version store lives in tempdb. It can grow quietly until it doesn't.

SELECT 
    DB_NAME(database_id) AS DatabaseName,
    reserved_page_count / 128 AS VersionStore_MB
FROM sys.dm_tran_version_store_space_usage
WHERE reserved_page_count > 0
ORDER BY reserved_page_count DESC;

If you see a database holding hundreds of gigs here, you've got a long-running transaction preventing version cleanup. Find it. Kill it. (With the appropriate career-preserving precautionary measures.)

Quick Wins

Add more tempdb files. One file per CPU core, up to 8. Be sure to keep them equally sized. SQL Server will thank you with reduced allocation contention.

Update statistics. Bad cardinality estimates → bad memory grants → spills. It's almost always statistics. I've actually asked a couple AI tools about query plans, and even they say 'update your statistics' before anything else.

Check for temp table abuse. That stored procedure creating a 50-column temp table inside a loop? Yeah. We've all seen it. We've all inherited it.

Monitor proactively. Set up an alert when tempdb exceeds 70% of its max size. Future you will appreciate past you. I promise.

The Bottom Line

TempDB problems are everyone's problems. When it fills up, virtually everything touching that instance is going to feel it. Five minutes of detective work now prevents the RCA you have to write later.

Go check yours. Right now. I'll wait.

More to Read:

The Ticking Time Bomb in Your Database: Finding Identity Columns Before They Blow

Getting paged at 2AM because inserts are failing? Surprise! Your identity column just hit 2,147,483,647 and has no more room for growth. Identity columns auto-increment, they're reliable, and we often forget about them -- until they hit their ceiling.

This post will help prevent that from happening to you.

The Problem Nobody Thinks About

Every identity column has a data type with a maximum value:

Data Type Maximum Value Translation
tinyint 255 Basically nothing
smallint 32,767 Still tiny
int 2,147,483,647 ~2.1 billion
bigint 9.2 quintillion You're fine. Probably.

That int identity you created 10 years ago might be closer to the edge than you think -- especially after failed inserts, bulk operations, or that one time someone reseeded it 'just to test it out'.

The Query That Saves Your Weekend

This script shows you which identity columns are close to maxing out:

SELECT 
    SCHEMA_NAME(t.schema_id) AS SchemaName,
    t.name AS TableName,
    c.name AS ColumnName,
    ty.name AS DataType,
    IDENT_CURRENT(SCHEMA_NAME(t.schema_id) + '.' + t.name) AS CurrentIdentity,
    CASE ty.name
        WHEN 'int' THEN 2147483647
        WHEN 'bigint' THEN 9223372036854775807
        WHEN 'smallint' THEN 32767
        WHEN 'tinyint' THEN 255
    END AS MaxValue,
    CAST(
        IDENT_CURRENT(SCHEMA_NAME(t.schema_id) + '.' + t.name) * 100.0 / 
        CASE ty.name
            WHEN 'int' THEN 2147483647
            WHEN 'bigint' THEN 9223372036854775807
            WHEN 'smallint' THEN 32767
            WHEN 'tinyint' THEN 255
        END 
    AS DECIMAL(5,2)) AS PercentUsed
FROM sys.tables t INNER JOIN sys.columns c 
  ON t.object_id = c.object_id INNER JOIN sys.types ty 
    ON c.user_type_id = ty.user_type_id
WHERE c.is_identity = 1
ORDER BY PercentUsed DESC;

Sample output:

Table Type Current % Used
Orders int 1,932,735,282 89.99
AuditLog smallint 28,521 87.05
Users int 15,234,891 0.71

That Orders table currently at 90% ?? At 50,000 inserts per day, you've got about 11 years. Or 11 months if business takes off. Sleep well.

The Threshold Guide

> 80% — Stop reading and fix it now.
50–80% — Put it on the roadmap.
< 50% — Monitor monthly.

Your Options When You Find One

Migrate to bigint. Painful with foreign keys, but 9 quintillion values buys you time. Lots of it.

Archive and reset. Move old data out, reseed the identity. Risky if you botch referential integrity.

Switch to SEQUENCE. More control, better for new development. Won't help legacy tables.

Make It a Habit

You might even want to set up a SQL Agent job to run this on a scheduled basis -- weekly or monthly, depending on how fast your data changes. Consider adding a threshold like this to catch anything over 70%:

-- Add to WHERE clause to only flag the scary ones
AND CAST(
    IDENT_CURRENT(SCHEMA_NAME(t.schema_id) + '.' + t.name) * 100.0 / 
    CASE ty.name
        WHEN 'int' THEN 2147483647
        WHEN 'bigint' THEN 9223372036854775807
        WHEN 'smallint' THEN 32767
        WHEN 'tinyint' THEN 255
    END 
AS DECIMAL(5,2)) > 70

Five minutes of monitoring beats five hours of 2AM panic.

Go run the query.

Soon.

How Does Data Actually Get Into Fabric?

In Part 1 we answered 'What is Fabric?' and in Part 2 we covered how Fabric organizes data with OneLake, Lakehouses, and Warehouses.

Now the practical question: How does your data actually get into Fabric?

This matters because Fabric only delivers value once data is there, and the ingestion path you choose determines cost, latency, and how much of your existing environment you have to rebuild.

THE INGESTION OPTIONS (with the fine print)

1. Data Factory Pipelines

If you've used Azure Data Factory or SSIS, this will feel familiar. Scheduled pipelines, copy activities, connectors for SQL Server, Oracle, flat files, APIs.

What works: Broad connector support, batch loads -- the mental model you already have.

What they don't make obvious: Fabric Data Factory and Azure Data Factory are separate products with separate roadmaps. Fabric DF is SaaS; ADF is PaaS. Some ADF features — tumbling window triggers, certain orchestration patterns — aren't available in Fabric. Microsoft maintains both without plans to deprecate ADF.

If you're migrating from ADF, you mustn't just assume that your pipelines will lift-and-shift cleanly.

2. Dataflows Gen2

Power Query at scale. Low-code, browser-based, aimed at analysts who want to shape data without writing SQL or Spark.

What works: Business users can own parts of the pipeline. Supports on-prem data sources via the on-premises data gateway. You choose where the data goes — a Lakehouse, Warehouse, or other Fabric destination — and it's saved as Delta tables.

What else to consider: Dataflows are useful when your business users own part of the data pipeline. They handle moderate complexity well but aren't designed for the most demanding or complex scenarios.

3. Mirroring

This is where it gets interesting for SQL Server shops. Mirroring continuously replicates data from supported sources into OneLake — no pipelines, no scheduling, no manual refresh.

What works:
  • Near real-time sync using Change Data Capture (SQL Server 2016–2022) or Change Feed (SQL Server 2025)
  • Zero-ETL model: data shows up in Fabric without you building anything
  • Supports on-premises SQL Server, Azure SQL, Cosmos DB, and Snowflake

What is not emphasized:
  • Requires an on-premises data gateway (or virtual network gateway) for non-Azure sources
  • SQL Server 2025 also requires Azure Arc
  • CDC must be enabled on your source tables, which adds overhead to your production system

For organizations running SQL Server -- on-prem or in Azure -- Mirroring is the fastest path to a unified analytics layer, but you must test it under realistic load before promising anyone real-time analytics.

4. Shortcuts

Shortcuts don't move data at all. They create a pointer from OneLake to external storage.

What works: No data duplication. Supports ADLS Gen2, Amazon S3, S3-compatible storage, Google Cloud Storage, Azure Blob Storage, Dataverse, Iceberg tables, OneDrive/SharePoint, and on-premises sources via gateway.

What not to forget: Performance depends entirely on the source. A well-tuned ADLS container will perform differently than an unoptimized S3 bucket. Governance also gets more complicated, as you are managing permissions across multiple storage systems while presenting everything through OneLake.

Shortcuts are useful for pilots or bridging legacy systems. They're less suitable as a long-term architectural foundation.

5. Notebooks and Spark

Maximum flexibility. Write Spark code, transform data however you want, and land it in OneLake.

What works: If you have data engineers who know Spark, this is powerful. Complex transformations, streaming, custom logic -- all possible.

What they don't make obvious: Notebooks do not support on-premises data gateway connections. If your source data is on-prem, you cannot use notebooks to pull it directly. You must use pipelines or Dataflows to land the data in a Lakehouse first, then use notebooks for transformation.

This is documented, but easy to miss when designing architecture. Notebooks are for transformation, not ingestion from on-prem sources.

WHICH PATH SHOULD YOU TAKE?

Most organizations won't pick just one.

ScenarioRecommended PathKey Consideration
Nightly batch loads from SQL ServerData Factory pipelinesSeparate product from ADF — test your patterns
Real-time sync from SQL ServerMirroringCDC overhead, gateway requirements
Analyst-driven data prep (including on-prem)Dataflows Gen2Moderate complexity; supports gateway
Existing data in ADLS, S3, GCSShortcuts (short-term), pipelines (long-term)Performance depends on source optimization
Complex transformations after data is in FabricNotebooks / SparkNo on-prem gateway support — land data first


PRACTICAL ADVICE

1. Start with one reporting workload, not your whole environment. Find a report that already depends on multiple data sources. Land copies of those sources into a Lakehouse using pipelines or Mirroring. Build the report. Measure whether anything actually improves.

2. Test Mirroring under realistic load. Enable CDC on a representative production table and observe the impact on your transaction log. Measure replication latency during peak hours. The documentation says 'near real-time' -- you should verify what that means for your workload.

3. Understand the gateway requirements. On-prem SQL Server mirroring, Dataflows to on-prem sources, and Shortcuts to on-prem storage all require the on-premises data gateway. Notebooks do not support gateway connections at all. Plan accordingly.

4. Don't migrate everything on day one. Fabric is an analytics destination, not a mandate to rip out everything you already have running. Identify the smallest useful workload that benefits from OneLake, prove it out, and expand from there.

COMING NEXT

In Part 4, we'll cover SQL Database in Microsoft Fabric — an actual transactional database running inside Fabric. What it is, what it isn't, and where it might actually make sense.

More to Read: