Friday, November 22, 2013

Query Performance Difference from Application v/s SSMS



When you observe performance difference between the application layer executing a stored procedure, v/s running the same exact call via SSMS, I found there actually exist 2 distinct query plans in the procedure cache. On running this query you will find identical values for the query_hash but different values for the query_plan_hash.


SELECT
       cp.objtype AS ObjectType,
       OBJECT_NAME(st.objectid,st.dbid) AS ObjectName,
       cp.usecounts AS ExecutionCount,
       st.TEXT AS QueryText,
       qp.query_plan AS QueryPlan,
       cp.plan_handle AS PlanHandle,
       execution_count,
       query_hash,
       query_plan_hash
FROM sys.dm_exec_cached_plans AS cp
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) AS st
join sys.dm_exec_query_stats qs on qs.plan_handle = cp.plan_handle
WHERE OBJECT_NAME(st.objectid,st.dbid) = 'CustomerOriginGet'
ORDER BY cp.usecounts DESC

ObjectType ObjectName ExecutionCount execution_count query_hash query_plan_hash
Proc CustomerOriginGet 10 10 0x27CBF0C0A5FFAC05 0x7FC50685222DDBF8
Proc CustomerOriginGet 8 8 0x27CBF0C0A5FFAC05 0xD1990C7B57DB8B71


I had to dig further to find the reason why 2 different plans were being generated for the same stored procedure. Using the above query to retrieve only the QueryPlan as "Saving As..." I saved the XML plan in a *.sqlplan file. Open this in SSMS for the graphical format.

On retrieving the properties of the root node select of the query plan, expand the Set Options.

Application Query Plan
ANSI_NULLS: True, ANSI_PADDING: True, ANSI_WARNINGS: True, ARITHABORT: False, CONCAT_NULL_YIELDS_NULL: True, NUMERIC_ROUNDABORT: False, QUOTED_IDENTIFIER: True

SSMS Query Plan
ANSI_NULLS: True, ANSI_PADDING: True, ANSI_WARNINGS: True, ARITHABORT: True, CONCAT_NULL_YIELDS_NULL: True, NUMERIC_ROUNDABORT: False, QUOTED_IDENTIFIER: True

The connection SET settings affect the query plan that is created.

As warned by this documentation of SET ARITHABORT
SET ARITHABORT

http://msdn.microsoft.com/en-us/library/ms190306.aspx


Caution note Caution
The default ARITHABORT setting for SQL Server Management Studio is ON. Client applications setting ARITHABORT to OFF can receive different query plans making it difficult to troubleshoot poorly performing queries. That is, the same query can execute fast in management studio but slow in the application. When troubleshooting queries with Management Studio always match the client ARITHABORT setting.


Additional Sources that helped me gather this information.


Use this DMV to query long XML query plans:

http://msdn.microsoft.com/en-us/library/windowsazure/hh977104.aspx

Slow in the Application, Fast in SSMS?
Understanding Performance Mysteries

http://www.sommarskog.se/query-plan-mysteries.html


SET Options That Affect Results


http://technet.microsoft.com/en-us/library/ms175088%28v=sql.105%29.aspx


Determining SET Options for a Current Session in SQL Server


http://www.mssqltips.com/sqlservertip/1415/determining-set-options-for-a-current-session-in-sql-server/


same query showing different execution plans on the same server


http://ask.sqlservercentral.com/questions/95689/same-query-showing-different-execution-plans-on-th.html

Monday, November 4, 2013

Grant permissions to functions


select 'GRANT SELECT ON [' + SCHEMA_NAME(schema_id) + '].[' + name + '] TO [public]', *
from sys.objects
WHERE type_desc in ('CLR_TABLE_VALUED_FUNCTION', 'SQL_TABLE_VALUED_FUNCTION')
order by name

select 'GRANT EXECUTE ON [' + SCHEMA_NAME(schema_id) + '].[' + name + '] TO [public]', *
from sys.objects
WHERE type_desc in ('AGGREGATE_FUNCTION', 'CLR_SCALAR_FUNCTION', 'SQL_SCALAR_FUNCTION')
order by name