Web Analytics Made Easy - Statcounter

Top 50 SQL DBA Problems with Practical Solutions | Complete Guide

Top 50 Important Sql Problems Related To Dbas With Their Solutions
Top 50 SQL DBA Problems & Solutions

1. Identify top CPU-consuming queries

SELECT TOP 10
  qs.total_worker_time/qs.execution_count AS avg_cpu,
  qs.execution_count,
  SUBSTRING(qt.text, (qs.statement_start_offset/2)+1,
            ((CASE qs.statement_end_offset
              WHEN -1 THEN DATALENGTH(qt.text)
              ELSE qs.statement_end_offset END
             - qs.statement_start_offset)/2) + 1) AS query_text,
  qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY avg_cpu DESC;

Tip: Find queries using most CPU to tune or index.

2. Find long-running queries

SELECT session_id, start_time, status, command,
       DATEDIFF(SECOND, start_time, GETDATE()) AS secs_running,
       SUBSTRING(txt.text, (req.statement_start_offset/2)+1, 200) AS sql_text
FROM sys.dm_exec_requests req
CROSS APPLY sys.dm_exec_sql_text(sql_handle) txt
WHERE req.status = 'running'
ORDER BY secs_running DESC;

Tip: Spot blocking or runaway sessions.

3. Detect blocking chain (who’s blocking whom)

SELECT blocking_session_id, session_id, wait_type, wait_time, last_wait_type
FROM sys.dm_exec_requests
WHERE blocking_session_id <> 0;

Tip: Identify blockers so you can kill or tune offending queries.

4. List active blocked and blocking sessions with SQL

SELECT
  r.session_id, r.blocking_session_id, s.login_name, s.host_name, r.wait_type, r.wait_time,
  SUBSTRING(t.text, r.statement_start_offset/2+1, 200) AS sql_text
FROM sys.dm_exec_requests r
JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.blocking_session_id <> 0;

Tip: Detailed view for incident response.

5. Kill a blocking SPID (use cautiously)

KILL 57; -- replace 57 with offending session_id

Tip: Emergency unblock; always check consequences.

6. Find missing indexes (DMV)

SELECT TOP 50
  CONVERT(INT, migs.avg_user_impact) AS impact,
  mid.statement AS table_name,
  mid.equality_columns, mid.inequality_columns, mid.included_columns
FROM sys.dm_db_missing_index_groups mig
JOIN sys.dm_db_missing_index_group_stats migs ON mig.index_group_handle = migs.group_handle
JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle
ORDER BY migs.avg_user_impact DESC;

Tip: Quick guidance for indexing; evaluate before creating.

7. Find unused indexes (index usage stats)

SELECT db_name(DB_ID()) AS DBName, OBJECT_NAME(s.object_id) AS TableName,
       i.name AS IndexName, user_seeks, user_scans, user_lookups, user_updates
FROM sys.dm_db_index_usage_stats s
JOIN sys.indexes i ON s.object_id = i.object_id AND s.index_id = i.index_id
WHERE OBJECTPROPERTY(s.object_id,'IsUserTable') = 1
AND user_seeks + user_scans + user_lookups = 0
ORDER BY user_updates DESC;

Tip: Candidate indexes to drop (after validation).

8. Rebuild fragmented indexes

ALTER INDEX ALL ON dbo.YourTable REBUILD WITH (ONLINE = ON);
-- or reorganize if fragmentation < 30%
ALTER INDEX ALL ON dbo.YourTable REORGANIZE;

Tip: Reduce fragmentation for I/O efficiency.

9. Find index fragmentation

SELECT DB_NAME() AS DBName, OBJECT_NAME(ps.object_id) AS table_name, i.name,
       ps.index_id, ps.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ps
JOIN sys.indexes i ON ps.object_id = i.object_id AND ps.index_id = i.index_id
WHERE ps.avg_fragmentation_in_percent > 10
ORDER BY ps.avg_fragmentation_in_percent DESC;

Tip: Plan index maintenance.

10. Check database integrity (DBCC CHECKDB)

DBCC CHECKDB (YourDatabase) WITH NO_INFOMSGS, ALL_ERRORMSGS;

Tip: Detect corruption early. Run during low-load windows.

11. Repair a corrupt database (last resort)

-- Preferred: restore from backup.
-- If not possible:
DBCC CHECKDB (YourDatabase, REPAIR_ALLOW_DATA_LOSS);

Tip: REPAIR_ALLOW_DATA_LOSS can lose data, use only if restore impossible.

12. Take full backup

BACKUP DATABASE YourDatabase
TO DISK = 'E:\Backups\YourDatabase_FULL.bak'
WITH FORMAT, INIT, COMPRESSION, CHECKSUM;

Tip: Baseline backups for point-in-time recovery.

13. Take differential backup

BACKUP DATABASE YourDatabase
TO DISK = 'E:\Backups\YourDatabase_DIFF.bak'
WITH DIFFERENTIAL, COMPRESSION, CHECKSUM;

Tip: Take faster, smaller backups between full backups.

14. Take transaction log backup (for full recovery model)

BACKUP LOG YourDatabase
TO DISK = 'E:\Backups\YourDatabase_LOG.trn'
WITH COMPRESSION, CHECKSUM;

Tip: Truncate log and enable point-in-time restores.

15. Restore full + diff + log for PITR

RESTORE DATABASE YourDatabase FROM DISK='...FULL.bak' WITH NORECOVERY;
RESTORE DATABASE YourDatabase FROM DISK='...DIFF.bak' WITH NORECOVERY;
RESTORE LOG YourDatabase FROM DISK='...LOG.trn' WITH RECOVERY, STOPAT='2026-07-14 10:15:00';

Tip: Example of point-in-time recovery workflow.

16. Find last full/diff/log backup times

SELECT database_name, type, MAX(backup_finish_date) AS last_backup
FROM msdb.dbo.backupset
WHERE database_name = 'YourDatabase'
GROUP BY database_name, type;
-- type: D=Full, I=Diff, L=Log

Tip: Verify backup cadence.

17. Check backup integrity (RESTORE VERIFYONLY)

RESTORE VERIFYONLY FROM DISK = 'E:\Backups\YourDatabase_FULL.bak';

Tip: Ensure backup file readable and consistent.

18. Automate integrity checks (example Agent job script)

-- Use DBCC CHECKDB in SQL Agent job step
DBCC CHECKDB (YourDatabase) WITH NO_INFOMSGS;

Tip: Schedule regular CHECKDBs.

19. Shrink database file (use sparingly)

DBCC SHRINKFILE (N'YourDB_Log' , 1024); -- shrink to 1GB

Tip: Generally discouraged; only for one-time space reclamation.

20. Find largest tables (by space)

EXEC sp_MSforeachtable 'EXEC sp_spaceused ''?''';
-- or faster:
SELECT t.NAME AS table_name, p.rows, 
       SUM(a.total_pages) * 8 AS total_kb,
       SUM(a.used_pages) * 8 AS used_kb, 
       (SUM(a.total_pages)-SUM(a.used_pages)) * 8 AS unused_kb
FROM sys.tables t
JOIN sys.indexes i ON t.object_id = i.object_id
JOIN sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
JOIN sys.allocation_units a ON p.partition_id = a.container_id
GROUP BY t.Name, p.rows
ORDER BY total_kb DESC;

Tip: Identify space hogs for archiving/partitioning.

21. Move database files to new disk

-- Step 1: set DB offline
ALTER DATABASE YourDatabase SET OFFLINE WITH ROLLBACK IMMEDIATE;
-- Move the files at OS level, then:
ALTER DATABASE YourDatabase MODIFY FILE (NAME = YourDB_Data, FILENAME = 'D:\DATA\YourDB.mdf');
ALTER DATABASE YourDatabase MODIFY FILE (NAME = YourDB_Log, FILENAME = 'F:\LOG\YourDB.ldf');
ALTER DATABASE YourDatabase SET ONLINE;

Tip: Rebalance I/O across disks. Plan downtime.

22. Check transaction log usage and log_reuse_wait

SELECT name, log_reuse_wait_desc FROM sys.databases WHERE name = 'YourDatabase';

Tip: Diagnose why log isn’t truncating (e.g., replication, open txn).

23. Find open transactions preventing log truncation

DBCC OPENTRAN('YourDatabase');
-- or use DMVs
SELECT * FROM sys.dm_tran_active_transactions;

Tip: Long open transactions keep log growth.

24. Shrink log file (only if necessary)

BACKUP LOG YourDatabase TO DISK='NUL';
DBCC SHRINKFILE ('YourDB_Log', 1024);

Tip: Backup log to allow truncation then shrink; be careful—log will regrow.

25. Detect and resolve deadlocks (capture graph)

-- Enable trace flag to capture deadlock graph to error log:
DBCC TRACEON (1222, -1);
-- or use Extended Events session for deadlock_graph

Tip: Analyze and fix deadlock victims by changing order or adding indexes.

26. Find blocked transactions and blocking chain with full details

SELECT r.session_id, r.status, r.command, r.wait_type, r.blocking_session_id,
       s.login_name, s.host_name, s.program_name,
       SUBSTRING(t.text, r.statement_start_offset/2+1, 200) AS sql_text
FROM sys.dm_exec_requests r
JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.blocking_session_id <> 0;

Tip: In-depth incident analysis.

27. Monitor wait stats (bottleneck detection)

SELECT wait_type, waiting_tasks_count, wait_time_ms, max_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN ('CLR_SEMAPHORE','LAZYWRITER_SLEEP','RESOURCE_QUEUE','SLEEP_TASK','SLEEP_SYSTEMTASK') 
ORDER BY wait_time_ms DESC;

Tip: Helps prioritize tuning (IO, CPU, memory, locks).

28. Clear plan cache (careful – impacts performance)

DBCC FREEPROCCACHE;
-- Or clear for specific plan handle

Tip: Use when bad plans persist; prefer clearing one plan, not whole cache in prod.

29. Find parameter sniffing issues (plan volatility)

SELECT obj.[name], cp.usecounts, qp.query_plan
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp
JOIN sys.objects obj ON cp.objectid = obj.object_id
WHERE cp.cacheobjtype = 'Compiled Plan' AND qp.query_plan.exist('//ParameterList') = 1;

Tip: Detect plans that vary per parameter; consider OPTION (RECOMPILE).

30. Force recompile for a stored proc

EXEC sp_recompile N'dbo.YourProc';
-- or use:
SELECT ... OPTION (RECOMPILE)

Tip: Solve bad cached-plan issues without flushing entire cache.

31. Find unused stored procedures / objects (no execution in cache)

SELECT o.name, o.type_desc
FROM sys.procedures p
LEFT JOIN sys.dm_exec_procedure_stats ps ON p.[object_id] = ps.object_id
LEFT JOIN sys.objects o ON p.object_id = o.object_id
WHERE ps.object_id IS NULL;

Tip: Candidate for cleanup (verify via extended usage logs first).

32. Check TempDB usage and top consumers

SELECT s.session_id, SUM(s.used_pages) * 8 AS used_kb
FROM sys.dm_db_task_space_usage s
GROUP BY session_id
ORDER BY used_kb DESC;
-- Also:
SELECT name, size*8 AS size_kb FROM tempdb.sys.database_files;

Tip: Diagnose TempDB contention and sizing.

33. Add TempDB data files to reduce contention

ALTER DATABASE tempdb ADD FILE (NAME = tempdev2, FILENAME = 'E:\TempDB\tempdb2.mdf', SIZE = 512MB);
-- Restart recommended for initial sizing changes to take effect evenly.

Tip: Multiple data files reduce allocation contention (typically one per logical CPU up to ~8).

34. Identify columns with missing statistics

SELECT OBJECT_NAME(s.object_id) AS TableName, c.name AS ColumnName, s.name AS StatsName
FROM sys.stats s
JOIN sys.stats_columns sc ON s.object_id = sc.object_id AND s.stats_id = sc.stats_id
JOIN sys.columns c ON sc.object_id = c.object_id AND sc.column_id = c.column_id
WHERE s.auto_created = 1 AND s.has_filter = 0;
-- Use sys.dm_db_stats_properties for last_updated_date

Tip: Out-of-date stats cause bad plans.

35. Update statistics for a table or database

-- For a table
UPDATE STATISTICS dbo.YourTable WITH FULLSCAN;
-- For whole DB
EXEC sp_updatestats;

Tip: Ensure optimizer has current distribution info.

36. Identify top wait types causing queries to slow

(See #27) — interpret: IO waits (PAGEIOLATCH_), lock waits (LCK_M_*), etc.
Tip: Map wait types to hardware/config bottlenecks.

37. Detect long-running transactions that prevent log truncation

SELECT s.session_id, s.login_name, t.transaction_begin_time, DATEDIFF(MINUTE,t.transaction_begin_time, GETDATE()) AS mins_running
FROM sys.dm_tran_session_transactions st
JOIN sys.dm_tran_active_transactions t ON st.transaction_id = t.transaction_id
JOIN sys.dm_exec_sessions s ON st.session_id = s.session_id
ORDER BY mins_running DESC;

Tip: Long transactions keep log growth.

38. Check database compatibility level

SELECT name, compatibility_level FROM sys.databases WHERE name = 'YourDatabase';

Tip: New features require newer compatibility; changing can affect behavior.

39. Find orphaned users (database users without login)

EXEC sp_change_users_login 'Report';
-- or for new versions:
SELECT dp.name AS UserName, sp.name AS LoginName
FROM sys.database_principals dp
LEFT JOIN sys.server_principals sp ON dp.sid = sp.sid
WHERE dp.type_desc = 'SQL_USER' AND sp.name IS NULL;

Tip: Clean-up and security hygiene.

40. Fix orphaned users

ALTER USER [dbuser] WITH LOGIN = [servername\domain\login];
-- Or map using sp_change_users_login for older versions
EXEC sp_change_users_login 'Auto_Fix', 'dbuser', NULL, 'StrongPassword';

Tip: Restore access mapping after restore/move.

41. Audit who changed schema (DDL auditing)

-- Use SQL Server Audit or DDL triggers; simple DDL trigger:
CREATE TABLE AuditDDL (EventTime DATETIME, LoginName SYSNAME, EventData XML);
GO
CREATE TRIGGER trgDDL ON DATABASE FOR DDL_DATABASE_LEVEL_EVENTS
AS
INSERT INTO AuditDDL (EventTime, LoginName, EventData)
VALUES (GETDATE(), SUSER_SNAME(), EVENTDATA());
GO

Tip: Track schema changes for compliance.

42. Disable/Enable Auto Close / Auto Shrink for best performance

ALTER DATABASE YourDatabase SET AUTO_CLOSE OFF;
ALTER DATABASE YourDatabase SET AUTO_SHRINK OFF;

Tip: Auto close/shrink cause overhead; turn off on production DBs.

43. Find databases using full recovery model (important for log backups)

SELECT name, recovery_model_desc FROM sys.databases WHERE recovery_model_desc = 'FULL';

Tip: Ensure log backups scheduled.

44. Convert DB to SIMPLE/ FULL recovery (caution)

ALTER DATABASE YourDatabase SET RECOVERY SIMPLE; -- or FULL

Tip: SIMPLE truncates logs automatically; FULL needed for PITR.

45. Monitor backup job failures (query msdb)

SELECT job.name, h.run_status, h.run_date, h.run_time, h.message
FROM msdb.dbo.sysjobhistory h
JOIN msdb.dbo.sysjobs job ON h.job_id = job.job_id
WHERE job.name LIKE '%Backup%' AND h.step_id = 0
ORDER BY h.run_date DESC, h.run_time DESC;

Tip: Proactively detect failed backups.

46. Configure Instant File Initialization (for data file growth)

  • Grant Perform volume maintenance tasks to SQL Server service account.
    Tip: Speeds data file growth by skipping zeroing; log files still zeroed.

47. Detect large transaction log growth events

SELECT name, size*8/1024 AS size_mb, growth, is_percent_growth FROM sys.database_files WHERE type_desc = 'LOG';
-- Additionally examine msdb backup history and log backup gaps

Tip: Correlate with large operations or missing log backups.

48. Identify and drop duplicate indexes

;WITH c AS (
  SELECT OBJECT_NAME(i.object_id) AS tablename, i.name, i.index_id,
         STUFF((SELECT ',' + COL_NAME(ic.object_id, ic.column_id)
                FROM sys.index_columns ic WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id
                ORDER BY ic.key_ordinal FOR XML PATH('')),1,1,'') AS cols
  FROM sys.indexes i
  WHERE i.is_primary_key = 0
)
SELECT * FROM c
-- find identical cols on same table, review then DROP INDEX

Tip: Remove redundant indexes to reduce write overhead.

49. Set up Maintenance Plan: rebuild, update stats, backup

Use SQL Server Maintenance Plans or custom Agent jobs combining:

  • ALTER INDEX ... REBUILD
  • UPDATE STATISTICS
  • BACKUP DATABASE
    Tip: Automate repetitive DBA tasks.

50. Configure high availability: basic AG / failover readiness checklist

  • Ensure cluster, shared storage or Windows Failover Cluster configured (AGs require FC or Synchronous commit)
  • Backup and restore master/ msdb as necessary
  • Test failover with ALTER AVAILABILITY GROUP ... FAILOVER;
    Tip: Prepare for disasters and ensure HA works.

Note: Many solutions include DBCC, ALTER DATABASE, RESTORE, DMVs, etc. Run these first in non-production or with safeguards (backups, maintenance windows) where appropriate.


Discover more from Technology with Vivek Johari

Subscribe to get the latest posts sent to your email.

Leave a Reply

Scroll to Top

Discover more from Technology with Vivek Johari

Subscribe now to keep reading and get access to the full archive.

Continue reading