Question

I downloaded the SQL Server First Aid Kit from Brent Ozar's website. When I tried to run the sp_BlitzIndex script against my master database via Microsoft Sql Server Management Studio while logged in as the Azure database server level admin and I got the following error:

Msg 262, Level 14, State 18, Procedure sp_BlitzIndex, Line 18 CREATE PROCEDURE permission denied in database 'master'.

I successfully created the procedure on the database instance I wanted to test. When I executed the procedure I got an error stating:

Msg 50000, Level 16, State 1, Line 1265 Invalid object name 'mydatabase.sys.partitions'.

Next I tried to be clever and run the stored procedure code directly against the master database without creating the stored procedure and got the following error:

Msg 50000, Level 15, State 1, Line 1267 Reference to database and/or server name in 'mydatabase.sys.indexes' is not supported in this version of SQL Server.

I don't feel confident enough to start toying with the inner workings of ~2700 lines of index heuristic logic. Is there a quick, and easy way to get this stored procedure to work nicely on Azure SQL Database or should I look elsewhere for an index analyzing tool/stored procedure?

Was it helpful?

Solution

Kendra here (the author of sp_BlitzIndex)

First, thanks for being interested in the procedure and trying it out.

Azure doesn't expose all the dynamic management views that we get in the boxed product. I do actually reference sys.dm_db_partition_stats, but there's other info I need to get from sys.partitions for other users. (Is it using compression? What type?)

I haven't had time to write an test an Azure specific version, just because I haven't had a lot of demand for it. But your question does tell me there's more interest than I knew of -- so there's that!

I will at minimum look at implementing some error handling so it lets you know in a graceful way though. (This is a bit of a moving target, because Azure has been expanding the features that are available to users as well.)

OTHER TIPS

Some of the 'standard' queries for identifying missing indexes do run on Azure, for example:

  SELECT
  migs.avg_total_user_cost * (migs.avg_user_impact / 100.0) * (migs.user_seeks + migs.user_scans) AS improvement_measure,
  'CREATE INDEX [missing_index_' + CONVERT (varchar, mig.index_group_handle) + '_' + CONVERT (varchar, mid.index_handle)
  + '_' + LEFT (PARSENAME(mid.statement, 1), 32) + ']'
  + ' ON ' + mid.statement
  + ' (' + ISNULL (mid.equality_columns,'')
    + CASE WHEN mid.equality_columns IS NOT NULL AND mid.inequality_columns IS NOT NULL THEN ',' ELSE '' END
    + ISNULL (mid.inequality_columns, '')
  + ')'
  + ISNULL (' INCLUDE (' + mid.included_columns + ')', '') AS create_index_statement,
  migs.*, mid.database_id, mid.[object_id]
FROM sys.dm_db_missing_index_groups mig
INNER JOIN sys.dm_db_missing_index_group_stats migs ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle
WHERE migs.avg_total_user_cost * (migs.avg_user_impact / 100.0) * (migs.user_seeks + migs.user_scans) > 10
ORDER BY migs.avg_total_user_cost * migs.avg_user_impact * (migs.user_seeks + migs.user_scans) DESC

They're likely to be much less useful than sp_BlitzIndex but worth a try.

Here's another handy query to identify the top queries, which you can then run with Execution Plan on to identify missing indexes via SQL Management Studio. Tedious doing them one by one but better than nothing:

SELECT TOP 1000 qs.execution_count, 
       qs.total_worker_time, 
       qs.total_worker_time / qs.execution_count AS 'Avg CPU Time', 
       qs. total_physical_reads, 
       qs.total_physical_reads / qs.execution_count AS 'Avg Physical Reads', 
       qs.total_logical_reads, 
       qs.total_logical_reads / qs.execution_count AS 'Avg Logical Reads', 
       qs.total_logical_writes, 
       qs.total_logical_writes / qs.execution_count AS 'Avg Logical Writes', 
       SUBSTRING(st.text, qs.statement_start_offset / 2 + 1, 
        (CASE qs.statement_end_offset
                     WHEN-1 THEN DATALENGTH(st.text)
                     ELSE qs.statement_end_offset
                     END
           - qs.statement_start_offset) / 2 + 1)AS statement_text
  FROM sys.dm_exec_query_stats AS qs 
  CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle)AS st
  ORDER BY qs.execution_count DESC;
Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top