This document provides 20 tips for SQL Server performance tuning and administration from MVP Ike Ellis. The tips cover topics such as SSIS, SSAS, SSRS, query performance, indexing, partitioning, hardware troubleshooting, scripting, auditing, and more. Ellis advocates spending time on report formatting, using window functions, scripting with PowerShell, enforcing business rules in the database, and logging activities for auditing purposes. He provides various resources and links for further information.
1. Tips & Tricks with SQL Server
Performance Tuning, SSAS, SSRS,
SSIS, and More!
By Ike Ellis, MVP
@ike_ellis
www.ikeellis.com
Blog.ikeellis.com
http://www.linkedin.com/in/ikeellis
2. So you want to be great at SQL
Server…SQL Server Integration Services
SQL Server Analysis Services
Tabular
MultiDimensional
SQL Server Reporting Services
Excel
Data Quality Services
Service Broker
Performance Tuning
Indexing
Query Plans
Plan Analysis
Memory Management
SANs
Network
Clustering
Availability Groups
PowerShell
Master Data Services
Architecture
Data Mart Design
Data Normalization
CDC
NoSQL/BigData (At least the MS Cloud Offerings)
Competitive Knowledge (Oracle, Tablaeu, QlickView,
Postgres)
ORMs(Entity Framework, Nhibernate, Micros)
Installation/Configuration/Upgrading/Service Packing
Power BI
PowerMap
PowerQuery
PowerView
PowerPivot
T-SQL
Querying
Stored Procedures
Functions
Windowing Functions
Aggregates
CLR
MDX
DAX
XMLA
BCP
SQL Azure
Tooling
Redgate
SSMS
SSDT
Past Versions
Central Management
DacPacs/BacPacs
Profiler/Extended Events
Auditing
Security/Encryption
Replication
SQLCMD
3. Tips From the SQL Consultant
• For the YouTube/Reddit/Chive/Cracked/Meme
generation
• Lots of disjointed tips
• Popular mistakes I see or easy things I think you
can take advantage of
• Between 3 – 5 minutes each
• Let’s see if we can get through all 20
5. Tip #2: Five minutes on report formatting = 10x
more impressive
• Spend 10 minutes on design (as opposed to the
zero we typically spend)
• Choose colors wisely
– 99/100 - developers use the default color
palette
• HTML color picker websites
– http://www.lavishbootstrap.com
• MorgueFile
– http://www.morguefile.com/
6. Tip #3: The right way to find hardware
problems
• Merging PerfMon and Tracing
• Get the Batch and Completed Events Only
• Never trace from the computer you are
monitoring
• Always trace to a file and then load in a table
after.
6
*Thanks, Grant!
7. Tip #4: Lifehack: Readable
Presentations
• Take the average age of the people in your
audience and divide by 2: That’s your font size
•USE THIS SIZE
IF YOUR
AUDIENCE IS
200
8. Tip #5: Check for heaps/clustered
indexes
SELECT t.[Name] FROM sys.Indexes i
JOIN sys.Tables t
ON t.Object_ID = i.Object_id
WHERE i.type_desc = 'HEAP'
ORDER BY t.[Name]
10. Tip #7: No reason to use ISNULL
CONCAT!
• Messy vs clean code
• No + symbol needed
• No ISNULL needed
11. Tip #8: How to search schema
• F7
• SQLSearch
– Free
– Download it!
– http://www.red-gate.com/products/sql-
development/sql-search/
– Did I mention it’s free?
• Dependency Tracker
– Not Free, but still cool
12. Tip #9: Windowing Functions are
pretty cool
• They are worth learning, and have a neat
evolution
13. Tip #10: SSDT Search for options
• No more digging around in options
• Just search for everything
14. Tip #11: Scripting: You have two
choices
• Two Choices
– Get good at boring repetitive tasks
– Get good at PowerShell & Scripting
• Who adds more value to their company or their
customers?
• Who gets paid more?
15. Tip #12: TempDB Configuration
• Current thought is 4 logical processors to 1 file
• Just a good beginning, your mileage may very
• Start there, then go to 2:1 or 1:1 if necessary
18. Tip #15: Life is so easy with a
dates table
• Find the sales numbers for the first Monday of
every month of the year
• T-SQL with no dates table
• T-SQL with dates table
20. Tip #17: Never reinvent the wheel
• Take SQL# for example
• Good Documentation
• Easy Syntax
• Cheap (and much of it is free)
21. Tip #18: Save scripts for easy
access
• Lots of repetitive scripts with business logic
• No reason to write the same queries for the
same tables day after day
22. Tip #19: Enforce Business Rules in the
DB
• Foreign Keys
• Unique Constraints
• Check Constraints
22
23. Tip #20: Log, Log, Log (and beware of
subscriptions)
select c.Name
, e.InstanceName
, e.UserName
, e.Parameters
, e.TimeStart
, e.TimeEnd
, e.TimeDataRetrieval
, e.TimeProcessing
, e.TimeRendering
from executionlog e
join catalog c
on e.reportid = c.ItemID
Send a Link, or a file on a shared folder that you can audit. Find someway to audit
who opened the link or the file in the folder. Try to avoid sending the PDF without
a way to audit it.
24. Ike Ellis
• http://blog.ikeellis.com
• http://www.ikeellis.com
• YouTube
– http://www.youtube.com/user/IkeEllisData
• SQL Pass Book Readers
– http://bookreaders.sqlpass.org/
• San Diego Tech Immersion Group
• Twitter: @ike_ellis
• 619.922.9801
• Email address is just my first name @ikeellis.com
Editor's Notes
Case Statements, bad code, etc.--this isn’t joining a bunch of subqueries--these are nestestsubqueries….FAR DIFFERENTSELECT *FROM (SELECT urgency, name, phone, location, department, cc, status,case_manager,ip,case_manager_ei d,id_problem,id_problem_type,eid_author, title, body,date_created,date_modified FROM problems AS main INNER JOIN (SELECT id_problem as t_urgency_id_problem,node_value AS urgency FROM problem_nodes WHERE node_name = "urgency")t_urgency ON t_urgency.t_urgency_id_problem = main.id_problem INNER JOIN (SELECT id_problem as t_name_id_problem,node_value AS name FROM problem_nodes WHERE node_name = "name")t_name ON t_name.t_name_id_problem = main.id_problem INNER JOIN (SELECT id_problem as t_phone_id_problem,node_value AS phone FROM problem_nodes WHERE node_name = "phone")t_phone ON t_phone.t_phone_id_problem = main.id_problem INNER JOIN (SELECT id_problem as t_location_id_problem,node_value AS location FROM problem_nodes WHERE node_name = "location")t_location ON t_location.t_location_id_problem = main.id_problem INNER JOIN (SELECT id_problem as t_department_id_problem,node_value AS department FROM problem_nodes WHERE node_name = "department")t_department ON t_department.t_department_id_problem = main.id_problem INNER JOIN (SELECT id_problem as t_cc_id_problem,node_value AS cc FROM problem_nodes WHERE node_name = "cc")t_cc ON t_cc.t_cc_id_problem = main.id_problem INNER JOIN (SELECT id_problem as t_status_id_problem,node_value AS status FROM problem_nodes WHERE node_name = "status")t_status ON t_status.t_status_id_problem = main.id_problem INNER JOIN (SELECT id_problem as t_case_manager_id_problem,node_value AS case_manager FROM problem_nodes WHERE node_name = "case_manager")t_case_manager ON t_case_manager.t_case_manager_id_problem = main.id_problem INNER JOIN (SELECT id_problem as t_ip_id_problem,node_value AS ip FROM problem_nodes WHERE node_name = "ip")t_ip ON t_ip.t_ip_id_problem = main.id_problem INNER JOIN (SELECT id_problem as t_case_manager_eid_id_problem,node_value AS case_manager_eid FROM problem_nodes WHERE node_name = "case_manager_eid")t_case_manager_eid ON t_case_manager_eid.t_case_manager_eid_id_problem =main.id_problem)t
use adventureworksdw2012select EnglishMonthName, min(datekey) from dimdatewhere englishdaynameofweek = 'monday'and calendaryear = '2010'group by EnglishMonthName, MonthNumberOfYearorder by MonthNumberOfYear
create table t1(col1 varchar(100))insert into t1(col1)values('1'),('2'),('3'),('ike'),('1'),('2'),('3'),('ike'), ('1'),('2'),('3'),('ike')select cast(col1 as int) from t1select try_cast(col1 as int) from t1
Watch the actual execution plan for these statements:drop table dbo.t1drop table dbo.t2--create two test tablescreate table dbo.t1(c1 int, c2 int check(c2 between 10 and 20));insert into dbo.t1values (11,12);create table dbo.t2(c1 int, c2 int);goinsert into dbo.t2values(101, 102);go select t1.c1 , t2.c2 , t2.c2 from dbo.t1 join dbo.t2 on t1.c1 = t2.c2 and t1.c2 = 20;select t1.c1 , t1.c2 , t2.c2 from dbo.t1 join dbo.t2 on t1.c1 = t2.c2 and t1.c2 = 30;
DBCC OPENTRANselect s.plan_handle , t.text , sum(s.execution_count) as totalExecutionCount , sum(s.total_elapsed_time) as totalElapsedTime , sum(s.total_worker_time) as totalWorkerTime , sum(s.total_logical_reads) as totalLogicalReads , sum(s.total_logical_writes) as totalLogicalWrites from sys.dm_exec_query_stats s cross apply sys.dm_exec_sql_text(s.plan_handle) t group by s.plan_handle, t.text order by sum(s.execution_count) desc
A common table expression (CTE) can be thought of as a temporary result set that is defined within the execution scope of a single SELECT, INSERT, UPDATE, DELETE, or CREATE VIEW statement. A CTE is similar to a derived table in that it is not stored as an object and lasts only for the duration of the query. Unlike a derived table, a CTE can be self-referencing and can be referenced multiple times in the same query.A CTE is made up of an expression name representing the CTE, an optional column list, and a query defining the CTE. After a CTE is defined, it can be referenced like a table or view can in a SELECT, INSERT, UPDATE, or DELETE statement. A CTE can also be used in a CREATE VIEW statement as part of its defining SELECT statement. A CTE can be used to: Create a recursive query.Substitute for a view when the general use of a view is not required; that is, you do not have to store the definition in metadata.Enable grouping by a column that is derived from a scalar subselect, or a function that is either not deterministic or has external access.Reference the resulting table multiple times in the same statement.ReferencesUsing Common Table Expressions: http://go.microsoft.com/fwlink/?LinkID=127330