Sharing an Execution Plan Without Exposing Sensitive Data

An execution plan is useful evidence, but it can carry more than query operators. Before sharing an execution plan, inspect names, literals, and runtime values as carefully as you inspect the warning icons.

A cottage window frosted on the lower half, clear above, a red curtain tied back

What Travels When Sharing an Execution Plan

I treat a plan file as data leaving the system. Showplan XML contains statement text, object names, indexes, predicates, and sometimes parameter values. Literal customer names or identifiers embedded in a query can appear in StatementText and scalar expressions. Actual plans can include runtime parameter values as well. A saved plan can also reveal database names and other environment details. The graphical SSMS view hides much of this until you open Properties or the XML. That is why a quick look at the operators is not a privacy review.

Decide whether the recipient truly needs the full file. A screenshot of the relevant operators with safe labels can answer a narrow question. When they need an executable plan for analysis, use a sanitized copy and retain the original locally for your own investigation.

Search the XML Before Sharing an Execution Plan

Open the .sqlplan file in a text editor and search for the server name, database names, customer identifiers, email domains, and sample literal values. Search the XML element and attribute names that commonly carry them: StatementText, ParameterList, ColumnReference, ScalarString, ConstValue, and ParameterRuntimeValue. I also inspect the file header and the Properties pane because a value can appear in more than one place. Redacting only the visible query text leaves the same value in a predicate.

Use a test copy of the plan for replacement. Keep a short map of what was replaced so you can explain the relationships to the recipient. Replace consistently: the same table should have the same safe name everywhere. A random replacement at each occurrence makes the plan harder to understand.

Extract Names for a First Pass

SQL can help inventory the object names in cached plans you are about to inspect, but the saved plan itself still needs a full file review. The query below shows XML from recent cached requests. Run it in a controlled environment and do not paste its output into a public discussion. On a busy server, choose the exact plan handle for your query rather than searching every cached plan.

SELECT TOP (10)
       DB_NAME(st.dbid) AS database_name,
       st.text AS statement_text,
       qp.query_plan
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp
ORDER BY qs.last_execution_time DESC;

Replace Carefully, Then Parse Again

For a small file, a text editor's find and replace can work. Replace the most specific values first, so a short server token does not mangle a longer object name. Keep the XML well formed. Do not remove tags or quotes without understanding the structure. An anonymize feature in a plan analysis tool can save time, but inspect its output anyway. Tool defaults change, and no tool knows which identifier is sensitive in your organization.

I use a local copy, make replacements, reopen it in SSMS, and verify that the plan still loads. Then I search the entire sanitized XML again for each sensitive value and for related fragments. A replacement that breaks the plan is frustrating. A replacement that leaves a customer name is worse.

Where private details hide in a plan: a diagram about the sharing an execution plan

Check Parameters and Literals Twice

Parameters deserve their own pass. A compiled parameter value and a runtime parameter value can differ. Both can appear in plan XML. A predicate can repeat the value in a scalar string. Dynamic SQL can put literal values directly in the statement text. Review all occurrences, not only the first match. If a literal is needed to explain selectivity, substitute a synthetic value of the same data type and roughly the same length. Then tell the reader it is synthetic. Do not claim the sanitized plan will compile to the same shape under that value.

Ask what the recipient needs to diagnose. They need cardinality estimates and operator types, not real parameter values. Retain enough context to make the plan useful while keeping actual identifiers inside your environment.

Inspect the Destination

A private support case, an internal ticket, and a public forum have different exposure. Confirm who can read the destination and whether attachments can be indexed or forwarded. A plan uploaded to a public site can outlive the issue that prompted it. I prefer a short written question that names the symptom and includes only the sanitized plan. Do not add screenshots of a results grid as an afterthought. Those screenshots can undo all the careful plan work.

If your organization has a data-classification or support-upload process, follow it. The technical redaction is one part of authorization to share. Keep the original plan in its approved location, not beside the public sanitized copy with an almost identical filename.

Search a Saved Plan as Plain Text

A simple local search can catch obvious identifiers before the deeper XML review. The PowerShell example works on a copied plan. It reports the lines that contain the terms you provide, then replaces two known names and writes the copy back. Notice that CustomerName is searched but not replaced, so running the search again still finds it. Keep the terms and results in a private review area; a search string can itself contain sensitive data. I follow this with a full manual pass, because names can be XML-escaped or appear in a form the exact search misses. Never send the search output as a substitute for the sanitized file.

# PowerShell
$planPath = 'C:\Review\sanitized-plan.sqlplan'
$terms = @('InternalServer', 'CustomerName', 'PrivateDatabase')
Select-String -LiteralPath $planPath -Pattern $terms -SimpleMatch
$xml = Get-Content -LiteralPath $planPath -Raw
$xml = $xml.Replace('InternalServer', 'ServerA').Replace('PrivateDatabase', 'DatabaseA')
[System.IO.File]::WriteAllText($planPath, $xml, [System.Text.UTF8Encoding]::new($false))

What if the plan includes an email address you did not know to search for? Search broad patterns and inspect the surrounding XML, especially statement text and parameter nodes. Reopen the final copy in SSMS after replacement. A tool can say "no matches" for your list while the file still contains a different private value. The release checklist should ask both whether known secrets were removed and whether the file was read as a whole.

A Final Check Before Sharing an Execution Plan

Open the exact file that will be attached. Search it for host names, database names, customer terms, email addresses, and any literal from the query. Inspect StatementText, ParameterList, object names, predicates, and Properties. Verify that the file opens and that the useful operators remain. Confirm that the filename itself carries no private project name. The last check must be on the saved artifact, not the editor buffer.

Sharing an execution plan works only when another professional can understand the problem from the sanitized file and your description. If they cannot, add a safe explanation rather than restoring real identifiers. A plan review works best when the question is precise and the privacy check is complete.

Related reading on this blog: AI Execution Plan Analysis: I Gave It My Plan and Asked What Was Wrong and Email an Execution Plan: SQL in Sixty Seconds #114.

The last check on the saved file: a checklist on the sharing an execution plan

A saved plan is not an anonymous diagram, it is a copy of your workload's details.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.

Execution Plan, SQL Server, SQL Server Security, SQL XML
Previous Post
SQL Server on Virtual Machines: Settings That Matter
Next Post
Handing Over a Database to Another Team

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.