You are previewing SQL Server 2008 Query Performance Tuning Distilled.
O'Reilly logo
SQL Server 2008 Query Performance Tuning Distilled

Book Description

SQL Server 2008 Query Performance Tuning Distilled presents a direct trouble-shooting methodology for identifying poorly performing stored procedures and queries, isolating the causes of that poor performance, and fixing the underlying problems. Each chapter is dedicated to one of the top causes of poorly performing queries and shows methods for identifying and dealing with the problems in that chapter's domain. Emphasis is always put upon or placed upon practical methods that you can put to immediate use in your day-to-day work. SQL Server 2008 functionality, tips, and tricks are emphasized in each subject area.

  • Emphasizes the practical. Does not bury readers in theory.

  • Gives readers practical techniques to immediately apply in their daily work.

  • Dedicates a chapter to each of the most common, performance-related problem areas.

Table of Contents

  1. Copyright
  2. About the Author
  3. About the Technical Reviewer
  4. Acknowledgments
  5. Introduction
    1. Who This Book Is For
    2. How This Book Is Structured
    3. Downloading the Code
    4. Contacting the Author
  6. 1. SQL Query Performance tuning
    1. 1.1. The Performance-Tuning Process
      1. 1.1.1. The Core Process
      2. 1.1.2. Iterating the Process
    2. 1.2. Performance vs. Price
      1. 1.2.1. Performance Targets
      2. 1.2.2. "Good Enough" Tuning
    3. 1.3. Performance Baseline
    4. 1.4. Where to Focus Efforts
    5. 1.5. SQL Server Performance Killers
      1. 1.5.1. Poor Indexing
      2. 1.5.2. Inaccurate Statistics
      3. 1.5.3. Excessive Blocking and Deadlocks
      4. 1.5.4. Non-Set-Based Operations
      5. 1.5.5. Poor Query Design
      6. 1.5.6. Poor Database Design
      7. 1.5.7. Excessive Fragmentation
      8. 1.5.8. Nonreusable Execution Plans
      9. 1.5.9. Poor Execution Plans
      10. 1.5.10. Frequent Recompilation of Execution Plans
      11. 1.5.11. Improper Use of Cursors
      12. 1.5.12. Improper Configuration of the Database Log
      13. 1.5.13. Excessive Use or Improper Configuration of tempdb
    6. 1.6. Summary
  7. 2. System Performance Analysis
    1. 2.1. Performance Monitor Tool
    2. 2.2. Dynamic Management Views
    3. 2.3. Hardware Resource Bottlenecks
      1. 2.3.1. Identifying Bottlenecks
      2. 2.3.2. Bottleneck Resolution
    4. 2.4. Memory Bottleneck Analysis
      1. 2.4.1. SQL Server Memory Management
      2. 2.4.2. Available Bytes
      3. 2.4.3. Pages/sec and Page Faults/sec Counters
      4. 2.4.4. Buffer Cache Hit Ratio
      5. 2.4.5. Page Life Expectancy
      6. 2.4.6. Checkpoint Pages/sec
      7. 2.4.7. Lazy writes/sec
      8. 2.4.8. Memory Grants Pending
      9. 2.4.9. Target Server Memory (KB) and Total Server Memory (KB)
    5. 2.5. Memory Bottleneck Resolutions
      1. 2.5.1. Optimizing Application Workload
      2. 2.5.2. Allocating More Memory to SQL Server
      3. 2.5.3. Increasing System Memory
      4. 2.5.4. Changing from a 32-bit to a 64-bit Processor
      5. 2.5.5. Enabling 3GB of Process Space
      6. 2.5.6. Using Memory Beyond 4GB Within SQL Server
    6. 2.6. Disk Bottleneck Analysis
      1. 2.6.1. Disk Counters
      2. 2.6.2. % Disk Time
      3. 2.6.3. Current Disk Queue Length
      4. 2.6.4. Disk Transfers/sec
      5. 2.6.5. Disk Bytes/sec
      6. 2.6.6. Avg. Disk Sec/Read and Avg. Disk Sec/Write
    7. 2.7. Disk Bottleneck Resolutions
      1. 2.7.1. Optimizing Application Workload
      2. 2.7.2. Using a Faster Disk Drive
      3. 2.7.3. Using a RAID Array
      4. 2.7.4. Using a SAN System
      5. 2.7.5. Aligning Disks Properly
      6. 2.7.6. Using a Battery-Backed Controller Cache
      7. 2.7.7. Adding System Memory
      8. 2.7.8. Creating Multiple Files and Filegroups
      9. 2.7.9. Placing the Table and Index on Separate Disks
      10. 2.7.10. Saving Log Files to a Separate Physical Disk
      11. 2.7.11. Partitioning Tables
    8. 2.8. Processor Bottleneck Analysis
      1. 2.8.1. % Processor Time
      2. 2.8.2. % Privileged Time
      3. 2.8.3. Processor Queue Length
      4. 2.8.4. Context Switches/sec
      5. 2.8.5. Batch Requests/sec
      6. 2.8.6. SQL Compilations/sec
      7. 2.8.7. SQL Recompilations/sec
    9. 2.9. Processor Bottleneck Resolutions
      1. 2.9.1. Optimizing Application Workload
      2. 2.9.2. Eliminating Excessive Compiles/Recompiles
      3. 2.9.3. Using More or Faster Processors
      4. 2.9.4. Using a Large L2/L3 Cache
      5. 2.9.5. Running More Efficient Controllers/Drivers
      6. 2.9.6. Not Running Unnecessary Software
    10. 2.10. Network Bottleneck Analysis
      1. 2.10.1. Bytes Total/sec
      2. 2.10.2. % Net Utilization
    11. 2.11. Network Bottleneck Resolutions
      1. 2.11.1. Optimizing Application Workload
      2. 2.11.2. Adding Network Adapters
      3. 2.11.3. Moderating and Avoiding Interruptions
    12. 2.12. SQL Server Overall Performance
      1. 2.12.1. Missing Indexes
      2. 2.12.2. Database Blocking
      3. 2.12.3. Nonreusable Execution Plans
      4. 2.12.4. General Behavior
    13. 2.13. Creating a Baseline
      1. 2.13.1. Creating a Reusable List of Performance Counters
      2. 2.13.2. Creating a Counter Log Using the List of Performance Counters
      3. 2.13.3. Minimizing Performance Monitor Overhead
    14. 2.14. System Behavior Analysis Against Baseline
    15. 2.15. Summary
  8. 3. SQL Query Performance Analysis
    1. 3.1. The SQL Profiler Tool
      1. 3.1.1. Profiler Traces
      2. 3.1.2. Events
      3. 3.1.3. Data Columns
      4. 3.1.4. Filters
      5. 3.1.5. Trace Templates
      6. 3.1.6. Trace Data
    2. 3.2. Trace Automation
      1. 3.2.1. Capturing a Trace Using the GUI
      2. 3.2.2. Capturing a Trace Using Stored Procedures
    3. 3.3. Combining Trace and Performance Monitor Output
    4. 3.4. SQL Profiler Recommendations
      1. 3.4.1. Limiting the Number of Events and Data Columns
      2. 3.4.2. Discarding Start Events for Performance Analysis
      3. 3.4.3. Limiting the Trace Output Size
      4. 3.4.4. Avoiding Online Data Column Sorting
      5. 3.4.5. Running Profiler Remotely
      6. 3.4.6. Limiting the Use of Certain Events
    5. 3.5. Query Performance Metrics Without Profiler
    6. 3.6. Costly Queries
      1. 3.6.1. Identifying Costly Queries
      2. 3.6.2. Identifying Slow-Running Queries
    7. 3.7. Execution Plans
      1. 3.7.1. Analyzing a Query Execution Plan
      2. 3.7.2. Identifying the Costly Steps in an Execution Plan
      3. 3.7.3. Analyzing Index Effectiveness
      4. 3.7.4. Analyzing Join Effectiveness
      5. 3.7.5. Actual vs. Estimated Execution Plans
      6. 3.7.6. Plan Cache
    8. 3.8. Query Cost
      1. 3.8.1. Client Statistics
      2. 3.8.2. Execution Time
      3. 3.8.3. STATISTICS IO
    9. 3.9. Summary
  9. 4. Index Analysis
    1. 4.1. What Is an Index?
      1. 4.1.1. The Benefit of Indexes
      2. 4.1.2. Index Overhead
    2. 4.2. Index Design Recommendations
      1. 4.2.1. Examine the WHERE Clause and Join Criteria Columns
      2. 4.2.2. Use Narrow Indexes
      3. 4.2.3. Examine Column Uniqueness
      4. 4.2.4. Examine the Column Data Type
      5. 4.2.5. Consider Column Order
      6. 4.2.6. Consider the Type of Index
    3. 4.3. Clustered Indexes
      1. 4.3.1. Heap Tables
      2. 4.3.2. Relationship with Nonclustered Indexes
      3. 4.3.3. Clustered Index Recommendations
    4. 4.4. Nonclustered Indexes
      1. 4.4.1. Nonclustered Index Maintenance
      2. 4.4.2. Defining the Bookmark Lookup
      3. 4.4.3. Nonclustered Index Recommendations
    5. 4.5. Clustered vs. Nonclustered Indexes
      1. 4.5.1. Benefits of a Clustered Index over a Nonclustered Index
      2. 4.5.2. Benefits of a Nonclustered Index over a Clustered Index
    6. 4.6. Advanced Indexing Techniques
      1. 4.6.1. Covering Indexes
      2. 4.6.2. Index Intersections
      3. 4.6.3. Index Joins
      4. 4.6.4. Filtered Indexes
      5. 4.6.5. Indexed Views
      6. 4.6.6. Index Compression
    7. 4.7. Special Index Types
      1. 4.7.1. Full-Text
      2. 4.7.2. Spatial
      3. 4.7.3. XML
    8. 4.8. Additional Characteristics of Indexes
      1. 4.8.1. Different Column Sort Order
      2. 4.8.2. Index on Computed Columns
      3. 4.8.3. Index on BIT Data Type Columns
      4. 4.8.4. CREATE INDEX Statement Processed As a Query
      5. 4.8.5. Parallel Index Creation
      6. 4.8.6. Online Index Creation
      7. 4.8.7. Considering the Database Engine Tuning Advisor
    9. 4.9. Summary
  10. 5. Database Engine Tuning Advisor
    1. 5.1. Database Engine Tuning Advisor Mechanisms
    2. 5.2. Database Engine Tuning Advisor Examples
      1. 5.2.1. Tuning a Query
      2. 5.2.2. Tuning a Trace Workload
    3. 5.3. Database Engine Tuning Advisor Limitations
    4. 5.4. Summary
  11. 6. Bookmark Lookup Analysis
    1. 6.1. Purpose of Bookmark Lookups
    2. 6.2. Drawbacks of Bookmark Lookups
    3. 6.3. Analyzing the Cause of a Bookmark Lookup
    4. 6.4. Resolving Bookmark Lookups
      1. 6.4.1. Using a Clustered Index
      2. 6.4.2. Using a Covering Index
      3. 6.4.3. Using an Index Join
    5. 6.5. Summary
  12. 7. Statistics Analysis
    1. 7.1. The Role of Statistics in Query Optimization
    2. 7.2. Statistics on an Indexed Column
      1. 7.2.1. Benefits of Updated Statistics
      2. 7.2.2. Drawbacks of Outdated Statistics
    3. 7.3. Statistics on a Nonindexed Column
      1. 7.3.1. Benefits of Statistics on a Nonindexed Column
      2. 7.3.2. Drawback of Missing Statistics on a Nonindexed Column
    4. 7.4. Analyzing Statistics
      1. 7.4.1. Density
      2. 7.4.2. Statistics on a Multicolumn Index
      3. 7.4.3. Statistics on a Filtered Index
    5. 7.5. Statistics Maintenance
      1. 7.5.1. Automatic Maintenance
      2. 7.5.2. Manual Maintenance
      3. 7.5.3. Statistics Maintenance Status
    6. 7.6. Analyzing the Effectiveness of Statistics for a Query
      1. 7.6.1. Resolving a Missing Statistics Issue
      2. 7.6.2. Resolving an Outdated Statistics Issue
    7. 7.7. Recommendations
      1. 7.7.1. Backward Compatibility of Statistics
      2. 7.7.2. Auto Create Statistics
      3. 7.7.3. Auto Update Statistics
      4. 7.7.4. Automatic Update Statistics Asynchronously
      5. 7.7.5. Amount of Sampling to Collect Statistics
    8. 7.8. Summary
  13. 8. Fragmentation Analysis
    1. 8.1. Causes of Fragmentation
      1. 8.1.1. Page Split by an UPDATE Statement
      2. 8.1.2. Page Split by an INSERT Statement
    2. 8.2. Fragmentation Overhead
    3. 8.3. Analyzing the Amount of Fragmentation
      1. 8.3.1. Analyzing the Fragmentation of a Small Table
    4. 8.4. Fragmentation Resolutions
      1. 8.4.1. Dropping and Re-creating the Index
      2. 8.4.2. Re-creating the Index with the DROP_EXISTING Clause
      3. 8.4.3. Executing the ALTER INDEX REBUILD Statement
      4. 8.4.4. Executing the ALTER INDEX REORGANIZE Statement
    5. 8.5. Significance of the Fill Factor
    6. 8.6. Automatic Maintenance
    7. 8.7. Summary
  14. 9. Execution Plan Cache Analysis
    1. 9.1. Execution Plan Generation
      1. 9.1.1. Parser
      2. 9.1.2. Algebrizer
      3. 9.1.3. Optimization
    2. 9.2. Execution Plan Caching
    3. 9.3. Components of the Execution Plan
      1. 9.3.1. Query Plan
      2. 9.3.2. Execution Context
    4. 9.4. Aging of the Execution Plan
    5. 9.5. Analyzing the Execution Plan Cache
    6. 9.6. Execution Plan Reuse
      1. 9.6.1. Ad Hoc Workload
      2. 9.6.2. Prepared Workload
      3. 9.6.3. Plan Reusability of an Ad Hoc Workload
      4. 9.6.4. Plan Reusability of a Prepared Workload
    7. 9.7. Query Plan Hash and Query Hash
    8. 9.8. Execution Plan Cache Recommendations
      1. 9.8.1. Explicitly Parameterize Variable Parts of a Query
      2. 9.8.2. Create Stored Procedures to Implement Business Functionality
      3. 9.8.3. Code with sp_executesql to Avoid Stored Procedure Maintenance
      4. 9.8.4. Implement the Prepare/Execute Model to Avoid Resending a Query String
      5. 9.8.5. Avoid Ad Hoc Queries
      6. 9.8.6. Prefer sp_executesql over EXECUTE for Dynamic Queries
      7. 9.8.7. Parameterize Variable Parts of Queries with Care
      8. 9.8.8. Do Not Allow Implicit Resolution of Objects in Queries
    9. 9.9. Summary
  15. 10. Stored Procedure Recompilation
    1. 10.1. Benefits and Drawbacks of Recompilation
    2. 10.2. Identifying the Statement Causing Recompilation
    3. 10.3. Analyzing Causes of Recompilation
      1. 10.3.1. Schema or Bindings Changes
      2. 10.3.2. Statistics Changes
      3. 10.3.3. Deferred Object Resolution
      4. 10.3.4. SET Options Changes
      5. 10.3.5. Execution Plan Aging
      6. 10.3.6. Explicit Call to sp_recompile
      7. 10.3.7. Explicit Use of the RECOMPILE Clause
    4. 10.4. Avoiding Recompilations
      1. 10.4.1. Do Not Interleave DDL and DML Statements
      2. 10.4.2. Avoiding Recompilations Caused by Statistics Change
      3. 10.4.3. Using Table Variables
      4. 10.4.4. Avoiding Changing SET Options Within a Stored Procedure
      5. 10.4.5. Using OPTIMIZE FOR Query Hint
      6. 10.4.6. Using Plan Guides
    5. 10.5. Summary
  16. 11. Query Design Analysis
    1. 11.1. Query Design Recommendations
    2. 11.2. Operating on Small Result Sets
      1. 11.2.1. Limit the Number of Columns in select_list
      2. 11.2.2. Use Highly Selective WHERE Clauses
    3. 11.3. Using Indexes Effectively
      1. 11.3.1. Avoid Nonsargable Search Conditions
      2. 11.3.2. Avoid Arithmetic Operators on the WHERE Clause Column
      3. 11.3.3. Avoid Functions on the WHERE Clause Column
    4. 11.4. Avoiding Optimizer Hints
      1. 11.4.1. JOIN Hint
      2. 11.4.2. INDEX Hints
    5. 11.5. Using Domain and Referential Integrity
      1. 11.5.1. NOT NULL Constraint
      2. 11.5.2. Declarative Referential Integrity
    6. 11.6. Avoiding Resource-Intensive Queries
      1. 11.6.1. Avoid Data Type Conversion
      2. 11.6.2. Use EXISTS over COUNT(*) to Verify Data Existence
      3. 11.6.3. Use UNION ALL Instead of UNION
      4. 11.6.4. Use Indexes for Aggregate and Sort Conditions
      5. 11.6.5. Avoid Local Variables in a Batch Query
      6. 11.6.6. Be Careful Naming Stored Procedures
    7. 11.7. Reducing the Number of Network Round-Trips
      1. 11.7.1. Execute Multiple Queries Together
      2. 11.7.2. Use SET NOCOUNT
    8. 11.8. Reducing the Transaction Cost
      1. 11.8.1. Reduce Logging Overhead
      2. 11.8.2. Reduce Lock Overhead
    9. 11.9. Summary
  17. 12. Blocking Analysis
    1. 12.1. Blocking Fundamentals
    2. 12.2. Understanding Blocking
      1. 12.2.1. Atomicity
      2. 12.2.2. Consistency
      3. 12.2.3. Isolation
      4. 12.2.4. Durability
    3. 12.3. Database Locks
      1. 12.3.1. Lock Granularity
      2. 12.3.2. Lock Escalation
      3. 12.3.3. Lock Modes
      4. 12.3.4. Lock Compatibility
    4. 12.4. Isolation Levels
      1. 12.4.1. Read Uncommitted
      2. 12.4.2. Read Committed
      3. 12.4.3. Repeatable Read
      4. 12.4.4. Serializable
      5. 12.4.5. Snapshot
    5. 12.5. Effect of Indexes on Locking
      1. 12.5.1. Effect of a Nonclustered Index
      2. 12.5.2. Effect of a Clustered Index
      3. 12.5.3. Effect of Indexes on the Serializable Isolation Level
    6. 12.6. Capturing Blocking Information
      1. 12.6.1. Capturing Blocking Information with SQL
      2. 12.6.2. Profiler Trace and the Blocked Process Report Event
    7. 12.7. Blocking Resolutions
      1. 12.7.1. Optimize the Queries
      2. 12.7.2. Decrease the Isolation Level
      3. 12.7.3. Partition the Contended Data
      4. 12.7.4. Covering Index on Contended Data
    8. 12.8. Recommendations to Reduce Blocking
    9. 12.9. Automation to Detect and Collect Blocking Information
    10. 12.10. Summary
  18. 13. Deadlock Analysis
    1. 13.1. Deadlock Fundamentals
      1. 13.1.1. Choosing the Deadlock Victim
    2. 13.2. Using Error Handling to Catch a Deadlock
    3. 13.3. Deadlock Analysis
      1. 13.3.1. Collecting Deadlock Information
      2. 13.3.2. Analyzing the Deadlock
    4. 13.4. Avoiding Deadlocks
      1. 13.4.1. Accessing Resources in the Same Chronological Order
      2. 13.4.2. Decreasing the Number of Resources Accessed
      3. 13.4.3. Minimizing Lock Contention
    5. 13.5. Summary
  19. 14. Cursor Cost Analysis
    1. 14.1. Cursor Fundamentals
      1. 14.1.1. Cursor Location
      2. 14.1.2. Cursor Concurrency
      3. 14.1.3. Cursor Types
    2. 14.2. Cursor Cost Comparison
      1. 14.2.1. Cost Comparison on Cursor Location
      2. 14.2.2. Cost Comparison on Cursor Concurrency
      3. 14.2.3. Cost Comparison on Cursor Type
    3. 14.3. Default Result Set
      1. 14.3.1. Benefits
      2. 14.3.2. Drawbacks
    4. 14.4. Analyzing SQL Server Overhead with Cursors
      1. 14.4.1. Analyzing SQL Server Overhead with T-SQL Cursors
    5. 14.5. Cursor Recommendations
    6. 14.6. Summary
  20. 15. Database Workload Optimization
    1. 15.1. Workload Optimization Fundamentals
    2. 15.2. Workload Optimization Steps
      1. 15.2.1. Sample Workload
    3. 15.3. Capturing the Workload
    4. 15.4. Analyzing the Workload
    5. 15.5. Identifying the Costliest Query
    6. 15.6. Determining the Baseline Resource Use of the Costliest Query
      1. 15.6.1. Overall Resource Use
      2. 15.6.2. Detailed Resource Use
    7. 15.7. Analyzing and Optimizing External Factors
      1. 15.7.1. Analyzing the Batch-Level Options Used by the Application
      2. 15.7.2. Analyzing the Effectiveness of Statistics
      3. 15.7.3. Analyzing the Need for Defragmentation
    8. 15.8. Analyzing the Internal Behavior of the Costliest Query
      1. 15.8.1. Analyzing the Query Execution Plan
      2. 15.8.2. Identifying the Costly Steps in the Execution Plan
      3. 15.8.3. Analyzing the Effectiveness of the Processing Strategy
    9. 15.9. Optimizing the Costliest Query
      1. 15.9.1. Modifying an Existing Index
      2. 15.9.2. Analyzing the Application of a Join Hint
      3. 15.9.3. Avoiding the Clustered Index Scan Operation
      4. 15.9.4. Modifying the Procedure
    10. 15.10. Analyzing the Effect on Database Workload
    11. 15.11. Iterating Through Optimization Phases
    12. 15.12. Summary
  21. 16. SQL Server Optimization Checklist
    1. 16.1. Database Design
      1. 16.1.1. Balancing Under- and Overnormalization
      2. 16.1.2. Benefiting from Entity-Integrity Constraints
      3. 16.1.3. Benefiting from Domain and Referential Integrity Constraints
      4. 16.1.4. Adopting Index-Design Best Practices
      5. 16.1.5. Avoiding the Use of the sp_ Prefix for Stored Procedure Names
      6. 16.1.6. Minimizing the Use of Triggers
    2. 16.2. Query Design
      1. 16.2.1. Use the Command SET NOCOUNT ON
      2. 16.2.2. Explicitly Define the Owner of an Object
      3. 16.2.3. Avoid Nonsargable Search Conditions
      4. 16.2.4. Avoid Arithmetic Operators on the WHERE Clause Column
      5. 16.2.5. Avoid Optimizer Hints
      6. 16.2.6. Stay Away from Nesting Views
      7. 16.2.7. Ensure No Implicit Data Type Conversions
      8. 16.2.8. Minimize Logging Overhead
      9. 16.2.9. Adopt Best Practices for Reusing Execution Plans
      10. 16.2.10. Adopt Best Practices for Database Transactions
      11. 16.2.11. Eliminate or Reduce the Overhead of Database Cursors
    3. 16.3. Configuration Settings
      1. 16.3.1. Affinity Mask
      2. 16.3.2. Memory Configuration Options
      3. 16.3.3. Cost Threshold for Parallelism
      4. 16.3.4. Max Degree of Parallelism
      5. 16.3.5. Optimize for Ad Hoc Workloads
      6. 16.3.6. Query Governor Cost Limit
      7. 16.3.7. Fill Factor (%)
      8. 16.3.8. Blocked Process Threshold
      9. 16.3.9. Database File Layout
      10. 16.3.10. Database Compression
    4. 16.4. Database Administration
      1. 16.4.1. Keep the Statistics Up-to-Date
      2. 16.4.2. Maintain a Minimum Amount of Index Defragmentation
      3. 16.4.3. Cycle the SQL Error Log File
      4. 16.4.4. Avoid Automatic Database Functions Such As AUTO_CLOSE or AUTO_SHRINK
      5. 16.4.5. Minimize the Overhead of SQL Tracing
    5. 16.5. Database Backup
      1. 16.5.1. Incremental and Transaction Log Backup Frequency
      2. 16.5.2. Backup Distribution
      3. 16.5.3. Backup Compression
    6. 16.6. Summary