SQL Tips for the YouTube generation. 20 unrelated and independant tips, one right after another to speed up your database application without a ton of work.
2. Assumptions @ You You are a new DBA You don’t want to rewrite your entire application with a new schema, new DAL, or new queries You want to learn just enough so that your SQL apps are fast and maintainable 2
3. Tip #1 – Performance Problem: Check the low-hanging fruit Long-running jobs Long-running transactions DBCC OPENTRAN Check for long-running queries/both in amount and in duration 3
4. Tip #2: Prettify! 4 http://extras.sqlservercentral.com/prettifier/prettifier.aspx
5. Tip #3 – Performance Problem : Identify hardware performance bottlenecks. Memory Disk* Processor Network I/O *Most common bottleneck. It’s the Disk I/O, Stupid. (But it could be memory that’s causing it.) 5
6. Tip #4: 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
7. Tip #5: Files, Files Everywhere All need their own physical drive for space management and performance Master Data File (MDF) Log Files (LDF) TempDB Files O/S/SQL Files BAK Files 7
8. Tip #6: The Log File Fills sequentially, so no need for striping, mirror is fine. Don’t let it get filled up: Simple Mode or Backup. 8
9. Tip #7 - Good memory management Check for other applications running on the SQL Server Move anti-virus (or at least make sure it wasn't scanning the SQL ports or the SQL files) Move Exchange and F&P services (cluster) Turn off unneeded services SQL is I/O bound, so I would turn off any network/disk intensive services (DHCP, DNS, etc) 9
10. Tip #8 - Quick Indexing Tricks. check for 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] check for nonclustered indexes on foreign key columns (ID Columns) select * from sys.columns c where c.name like '%id%' and c.object_id not in ( select object_id from sys.index_columns ) check for non-clustered covering indexes reads outnumber inserts/updates 5 to 10 to 1 10
11. Tip #9 - Run the Index Tuning Wizard (DB Tuning Advisor) Run it a really long time, it is more accurate the longer it runs Don’t drop existing objects It’s OK to over-index 11
12. Tip #10 – I don’t really know the symptoms, but SQL Doctor will find the cure. Idera Red Gate DB Artison Quest 12
13. Tip #11– Baseline the right way Idera Diagnostics Manager & RedGate 13
14. Tip #12 – Enforce Business Rules in the DB Foreign Keys Unique Constraints Check Constraints 14
15. Tip #13 - Eliminate Cursors Cursors focus on how, not why or what Cursors are expensive Cursors take up memory, which is usually a problem already Cursors can often be written using a set-based method 15
16. Easy Tip #14 - Avoid Deadlocking, Blocking Index Tune Keep transactions short Don’t lock when you don’t have to Hit the tables in the same order (create a table order document) Minimize the use of triggers 16
20. Provide traversal of recursive hierarchiesWITH TopSales (SalesPersonID, NumSales) AS ( SELECT SalesPersonID, Count(*) FROM Sales.SalesOrderHeader GROUP BY SalesPersonId ) SELECT * FROM TopSales WHERE SalesPersonID IS NOT NULL ORDER BY NumSales DESC
21. Tip #16: apply operator right parameter can be a table, but meant for tvf cross apply does inner join no output for row when udf produces no output udf can get its parameters from left input outer apply does left outer join all rows from left input returned may have nulls for columns returned by udf
38. where not exists vs. where not in the possible presence of a null generates different plans for not exists and not in select salesPersonID from sales.salesPersons where not exists( select managerID from humanresources.employee e where e.managerID = s.salesPersonID) select salesPersonID from sales.salesPerson where salesPersonID not in (select managerID from humanresources.employee)
39. Tip #19: Statistics Update 22 From the query plan, estimated number of rows and the actual number of rows need to equal each other. If they don’t, you might have a statistics issue. Run sp_updatestats to rectify it.
40. Tip #20: Big Rows from Query Plan When troubleshooting, thick rows means lots of data, thin rows mean not much data. You’re probably better off following the thick rows. 23
41. Tip #21: Missing Index Details Just copy that, name the index something unique, and then run it. Remember, it doesn’t look for overlapping indexes, so check that before you run. 24
42. Conclusion Have a great code camp! Ike Ellis ike@ellisteam.net 619.922.9801 Twitter: @ike_ellis www.ellisteam.net 25
Notas del editor
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
Case Statements, bad code, etc.
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;
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