Azure SQL Managed Instance continues to evolve, and so does AI SQL Tuner. Our latest release introduces key improvements that make query tuning more intelligent, adaptive, and aligned with the capabilities of SQL Server 2022 on Managed Instance.
In this post, we’ll highlight the new enhancements, explain why they matter for DBAs and SQL developers, and share a sample tuning output that demonstrates how AI SQL Tuner now delivers actionable, version‑aware recommendations.
Table of Contents
🔑 Key Enhancements
1. Improved Deadlock Analysis
Deadlocks are one of the most frustrating performance issues in SQL Server. The latest release of AI SQL Tuner now adjusts its logic for gathering deadlock information, This allows it to correctly analyze deadlocks on Azure SQL Managed Instance.
2. Compatibility‑Aware Recommendations
Not all Managed Instances are created equal. AI SQL Tuner now checks the highest database compatibility level before generating recommendations. This ensures that tuning advice is optimized for the exact SQL Server version and feature set available on your Managed Instance.
For example:
- SQL Server 2022 features like Parameter Sensitive Plan optimization and DOP feedback are now factored into recommendations.
- Index strategies are aligned with batch mode on rowstore and columnstore enhancements, avoiding outdated guidance that doesn’t apply to modern compatibility levels.
📊 Sample Tuning Output: Azure SQL Managed Instance
Below is a snapshot of AI SQL Tuner’s recommendations for a Managed Instance running with compatibility level 160, equivalent to SQL Server 2022 compatibility. This output demonstrates how the tool now delivers version‑aware, compression‑optimized, and columnstore‑driven tuning strategies.
AI SQL Tuner Recommendations
Executive Summary — Top Priorities
- Convert dbo.orders from HEAP to a clustered primary key on o_orderkey; then add a narrow nonclustered index on o_orderdate to support range predicates. This removes heap scans/forwarded rows and improves joins from dbo.lineitem.
- Add a nonclustered columnstore index (NCCI) on dbo.lineitem to accelerate large aggregations and star joins (60M rows). This will greatly reduce CPU and logical reads for the heavy TPC-H style queries.
- Apply PAGE compression to large, read-mostly clustered indexes (dbo.part, dbo.partsupp, dbo.supplier, dbo.customer, dbo.lineitem cluster) to cut I/O without material write overhead.
- Avoid proliferating many overlapping nonclustered rowstore indexes on dbo.lineitem. The NCCI will subsume most missing-index requests; if additional point-lookups are still hot, add one targeted b-tree on l_orderkey with minimal includes.
- Update statistics with FULLSCAN on large tables after the changes to ensure optimal cardinality estimates, then let Auto Update maintain them.
- Refactor the top expensive queries to use explicit JOINs and pre-aggregation rather than IN + GROUP BY subqueries to allow better index and batch mode usage.
Detailed Prioritized Recommendations
1) Orders table: eliminate HEAP, cluster on PK, add date index
- Evidence: dbo.orders shows a HEAP with scans (23) and updates (15000) and a nonclustered PK (orders_pk). Missing index requests an access path by o_orderdate. Joins from dbo.lineitem reference o_orderkey.
- Action:
- Drop child foreign key referencing orders.o_orderkey, switch PK to CLUSTERED on o_orderkey (ONLINE), recreate the FK.
- Create a narrow, covering nonclustered index on o_orderdate to support inequality/range searches.
- Use PAGE compression to reduce I/O. Fillfactor 100 (read-mostly workload).
-- 1.1 Drop FK referencing orders.o_orderkey to allow PK change
ALTER TABLE dbo.lineitem DROP CONSTRAINT lineitem_order_fk;
-- 1.2 Drop existing NONCLUSTERED PK on orders (name: orders_pk)
ALTER TABLE dbo.orders DROP CONSTRAINT orders_pk;
-- 1.3 Recreate PRIMARY KEY as CLUSTERED on o_orderkey (ONLINE), with PAGE compression
ALTER TABLE dbo.orders
ADD CONSTRAINT orders_pk
PRIMARY KEY CLUSTERED (o_orderkey ASC)
WITH (DATA_COMPRESSION = PAGE, FILLFACTOR = 100, ONLINE = ON);
-- 1.4 Recreate referencing FK
ALTER TABLE dbo.lineitem
ADD CONSTRAINT lineitem_order_fk
FOREIGN KEY (l_orderkey) REFERENCES dbo.orders (o_orderkey);
-- 1.5 Add supporting NCI for date predicates (from Missing Indexes)
-- Keep it narrow. Include common join/output columns.
CREATE NONCLUSTERED INDEX IX_orders_o_orderdate
ON dbo.orders (o_orderdate)
INCLUDE (o_orderkey, o_custkey)
WITH (DATA_COMPRESSION = PAGE, FILLFACTOR = 100, ONLINE = ON);
2) Lineitem table: add Nonclustered Columnstore Index (NCCI)
- Evidence: 60,056,113 rows; large scan-heavy analytical queries in plan cache (multi-million logical reads) aggregating SUM(l_quantity), SUM/AVG(l_extendedprice), grouping by l_orderkey, filtering by attributes; numerous overlapping missing-index hints on various lineitem columns. Clustered index is on l_shipdate (good for shipping-date filters) with very low update rate (~60k updates vs 60M rows).
- Rationale: An NCCI drastically reduces I/O and CPU for the heavy analytic patterns via batch mode, segment elimination, and columnar compression, while preserving the existing clustered b-tree for OLTP lookups and shipdate filters. Update overhead is acceptable given low DML.
- Action: Add a wide NCCI to cover analytical access. No need to add many redundant rowstore NCIs suggested by the missing-index DMV.
-- 2.1 Nonclustered Columnstore Index on lineitem
-- Covers analytical queries without affecting the clustered b-tree on l_shipdate
CREATE NONCLUSTERED COLUMNSTORE INDEX NCCI_lineitem
ON dbo.lineitem
-- (no column list = all nonLOB columns are columnarized)
WITH (DROP_EXISTING = OFF, ONLINE = ON); -- ONLINE supported on MI for NCCI
3) Optional: a single targeted rowstore index on lineitem.l_orderkey (only if needed after NCCI)
- Evidence: Frequent join/aggregation by l_orderkey; multiple missing-index entries with l_orderkey equality and includes like l_quantity, l_discount, l_extendedprice, sometimes part/supp keys and dates.
- Recommendation: Start with NCCI only. If post-change monitoring still shows high cost nested loop lookups on rowstore paths by l_orderkey (e.g., when joining orders to lineitem without aggregation), add one narrow NCI that avoids ballooning storage.
-- 3.1 Add only if needed after validating NCCI performance
CREATE NONCLUSTERED INDEX IX_lineitem_l_orderkey
ON dbo.lineitem (l_orderkey)
INCLUDE (l_quantity, l_extendedprice, l_discount)
WITH (DATA_COMPRESSION = PAGE, FILLFACTOR = 100, ONLINE = ON);
4) Compression for large, read-mostly clustered tables
- Evidence: High seek counts and 0 updates on dbo.part, dbo.partsupp, dbo.supplier; customer also read-mostly. Data compression PAGE is effective on TPC-H schemas.
- Action: Apply PAGE compression online to reduce storage and I/O; minimal effect on CPU given modern MI hardware and read-biased workload.
-- 4.1 Apply PAGE compression to large lookup tables
ALTER INDEX part_pk ON dbo.part REBUILD WITH (DATA_COMPRESSION = PAGE, ONLINE = ON);
ALTER INDEX partsupp_pk ON dbo.partsupp REBUILD WITH (DATA_COMPRESSION = PAGE, ONLINE = ON);
ALTER INDEX supplier_pk ON dbo.supplier REBUILD WITH (DATA_COMPRESSION = PAGE, ONLINE = ON);
ALTER INDEX customer_pk ON dbo.customer REBUILD WITH (DATA_COMPRESSION = PAGE, ONLINE = ON);
-- 4.2 Consider compressing lineitem clustered index as well (read-mostly)
ALTER INDEX l_shipdate_ind ON dbo.lineitem REBUILD WITH (DATA_COMPRESSION = PAGE, ONLINE = ON);
5) Avoid creating overlapping lineitem nonclustered indexes
- Observation: Missing indexes list many low-count suggestions (Total Seeks+Scans mostly 2–3) on similar keys (l_orderkey, l_partkey, l_suppkey, ship attributes) with varying include lists.
- Recommendation: Do not materialize these piecemeal. The NCCI will serve these analytic patterns better and with less bloat. Revisit only if a specific OLTP lookup remains a hotspot; then add just the targeted index in Recommendation 3.
6) Statistics maintenance after structural changes
- Auto Create/Update Stats is enabled; after major index changes and columnstore creation, force a one-time FULLSCAN stats refresh on large tables to stabilize plans. Columnstore will create columngroup stats automatically; still update rowstore stats on base tables and new indexes.
-- 6.1 One-time deep stats refresh post-changes
UPDATE STATISTICS dbo.orders WITH FULLSCAN;
UPDATE STATISTICS dbo.lineitem WITH FULLSCAN;
UPDATE STATISTICS dbo.part WITH FULLSCAN;
UPDATE STATISTICS dbo.partsupp WITH FULLSCAN;
UPDATE STATISTICS dbo.supplier WITH FULLSCAN;
UPDATE STATISTICS dbo.customer WITH FULLSCAN;
-- 6.2 If maintenance windows are tight, use asynchronous sampling for smaller tables
-- (leave Auto Update Stats on; no change needed)
7) Query refactoring to leverage indexes and batch mode
- Query 1 (top consumer): Replace comma joins and IN (subquery with GROUP BY) with explicit joins and pre-aggregation. This aids the optimizer in pushing down grouping, using NCCI batch mode on lineitem, and reducing row counts before joins/sorts.
-- Before:
-- select top 100 c_name, c_custkey, o_orderkey, o_orderdate, o_totalprice, sum(l_quantity)
-- from customer, orders, lineitem
-- where o_orderkey in ( select l_orderkey from lineitem group by l_orderkey having sum(l_quantity) > 312)
-- and c_custkey = o_custkey and o_orderkey = l_orderkey
-- group by c_name, c_custkey, o_orderkey, o_orderdate, o_totalprice
-- order by o_totalprice desc, o_orderdate option (maxdop 4);
-- After (simplified, sargable, pre-aggregate lineitem):
WITH li AS (
SELECT l_orderkey, SUM(l_quantity) AS sum_qty
FROM dbo.lineitem
GROUP BY l_orderkey
HAVING SUM(l_quantity) > 312
)
SELECT TOP (100)
c.c_name, c.c_custkey, o.o_orderkey, o.o_orderdate, o.o_totalprice, li.sum_qty
FROM dbo.orders AS o
JOIN li ON li.l_orderkey = o.o_orderkey
JOIN dbo.customer AS c ON c.c_custkey = o.o_custkey
ORDER BY o.o_totalprice DESC, o.o_orderdate
OPTION (MAXDOP 4);
- Query 2 (brand/container and anti-join with AVG per part): Use CROSS APPLY for per-part average and rely on NCCI batch mode on lineitem; ensure explicit JOIN syntax to help the optimizer.
-- Before:
-- select sum(l_extendedprice) / 7.0 as avg_yearly
-- from lineitem, part
-- where p_partkey = l_partkey
-- and p_brand = 'Brand#51'
-- and p_container = 'JUMBO CASE'
-- and l_quantity < ( select 0.2 * avg(l_quantity) from lineitem where l_partkey = p_partkey)
-- option (maxdop 4);
-- After:
SELECT SUM(li.l_extendedprice) / 7.0 AS avg_yearly
FROM dbo.part AS p
CROSS APPLY (
SELECT 0.2 * AVG(l2.l_quantity) AS qty_threshold
FROM dbo.lineitem AS l2
WHERE l2.l_partkey = p.p_partkey
) AS T
JOIN dbo.lineitem AS li
ON li.l_partkey = p.p_partkey
WHERE p.p_brand = N'Brand#51'
AND p.p_container = N'JUMBO CASE'
AND li.l_quantity < T.qty_threshold
OPTION (MAXDOP 4);
8) Consider nonclustered columnstore on orders for analytics (optional)
- If post-change monitoring shows significant scan/aggregation over dbo.orders (15M rows) beyond the date NCI, add an NCCI on orders as well. This coexists with the clustered PK and benefits batch mode joins with lineitem.
-- 8.1 Optional, only if analytics over orders remain scan-heavy
CREATE NONCLUSTERED COLUMNSTORE INDEX NCCI_orders
ON dbo.orders
WITH (ONLINE = ON);
9) Validate and monitor
- Use Query Store to compare regressions and gains. Re-check sys.dm_db_index_usage_stats for added indexes after a representative workload window.
- If any added index shows high user_updates relative to user_seeks+scans and no noticeable plan adoption, consider dropping it to reduce maintenance overhead (not expected for the NCCI or the date NCI in this workload).
Notes on Version/Edition Capabilities
- Azure SQL Managed Instance (SQL 2022) supports online index operations and nonclustered columnstore indexes; Intelligent Query Processing will leverage batch mode on rowstore and columnstore automatically.
- Parameter Sensitive Plan optimization and DOP feedback are available; our index and code changes align well with these features.
These recommendations are directly optimized for Managed Instance with SQL Server 2022 compatibility, leveraging modern features like online index operations, batch mode execution, and intelligent query processing.
⚙️ Why This Matters for DBAs and SQL Developers
- Future‑proof tuning: Recommendations adapt to the latest SQL Server features, avoiding legacy advice.
- Performance gains: Columnstore indexes and compression strategies cut CPU and I/O for analytic workloads.
- Operational efficiency: Online index operations minimize downtime during schema changes.
🚀 Conclusion
AI SQL Tuner’s latest enhancements make it a more powerful ally for DBAs and SQL developers working with Azure SQL Managed Instance. By combining smarter deadlock insights with compatibility‑aware recommendations, the tool ensures that your tuning strategies are not only effective but also aligned with the latest SQL Server capabilities.
With these improvements, AI SQL Tuner continues to deliver actionable, version‑optimized guidance that helps you unlock the full performance potential of your Managed Instance workloads.
Ready to give it a try? You will need AI SQL Tuner Standard if you have Managed Instance General Purpose. If you are running Business Critical, Pro or Corporate is required. They all come with a 30-day money back guarantee so you can test the software in your own environment risk-free.
