SQL Server: Compare Index Performance - sql

How can I compare the performance of an Index on a table using the Query Analyzer?
I would like to run the same query through the Estimated Execution Plan twice, once using the index and once without, and have a good comparison of the table scans/index scans that are generated.
I have tried CREATE INDEX..., SELECT..., DROP INDEX..., SELECT. I expect the first query to use the index and the second to have no index, but both execution plans will use the index.

If there is no index, then it can't be used. However, the index still exists for the estimated execution plan for the 2nd select, so it is evaluated. The DROP INDEX plan is also just an estimate too
I'd use the actual execution plan anyway, because personally I don't like the estimated one.
You can use SET SHOWPLAN TEXT to capture what is actually used in the query window (or use the graphical one). I'd also use SET STATISTICS IO and often SET STATISTICS TIME too.

Use the Sql Server Profiler under configuration tools. Run your queries with and without indexing and record the data reads / writes timing etc of your function calls. This should give you a clear idea if your indexes have improved performance (less reads / latency etc.)

use this at the beginning of the query window. it'll clear any plan caches.
dbcc freeproccache
go
dbcc dropcleanbuffers
go
so have that at the top, and then put your dreat and drop index code in a comment, and then your query. run it initially without an index and see what it looks like, then create the index and rerun it.
and yes, use the actual execution plan and you can also use client statistics.

The technique that ended up working for me was to use the WITH keyword in the FROM clause.
When the index is created:
SELECT * FROM table WHERE ...
SELECT * FROM table WITH (INDEX(0)) WHERE ...
The first query will (probably) use the index, the second will not.
You could also use multiple indexes like:
SELECT * FROM table WITH (INDEX(IX_test1)) WHERE ...
SELECT * FROM table WITH (INDEX(IX_test2)) WHERE ...

Related

Advantages of explicitly writing an index

I wonder why one should ever care on explicitly writing an index in query. I frequently see queries like this
select blabla from Table with(nolock index = index_name)
Index is already defined, and query optimizer chooses the best index by itself. Isn't it more logical and efficient to write query as this:
select blabla from Table with(nolock)
What are the advantages of explicitly writing an index in query?
EDIT
Thank you all for your opinions. The best choice is not to force seeking indexes explicitly.
In this case only database vendors could be advantageous and it is not related with performance. They indicate indexes explicitly and force execution plan to not to change in order to be able to predict execution times.
This is question is kind of rhetoric: one must measure efficiency, not reason about it.
In ssms you can do it with "Include Actual Execution Plan" (Ctrl-M).
Try execute following in ssms and look at "Execution plan":
SELECT * FROM msdb.dbo.sysjobs with (index = nc1)
SELECT * FROM msdb.dbo.sysjobs with (index = clust)
SELECT * FROM msdb.dbo.sysjobs
You will find that: a)first index hint is only slowing, b) hint on clustered index and no hint have equivalent plans
Specifying Index in the SQL SERVER causes Force Seeking of that Index.
When any query is ran SQL Server Engine determines which index has to
be used. SQL Server makes uses Index which has lowest cost based on
performance. Index which is the best for performance is automatically
used. There are some instances when Database Developer is best judge
of the index used. DBA can direct SQL Server which index to be used to
execute query.
If the index that you have created is not picked up by SQL Server,
then try telling the SQL Server by using the HINT.
you can refer below links
http://blog.sqlauthority.com/2009/02/07/sql-server-introduction-to-force-index-query-hints-index-hint/
https://www.simple-talk.com/sql/performance/index-selection-and-the-query-optimizer/
I think it can be useful in case when sql engine creates execution plan for queries in stored procedure. It maybe situation when SQL engine created execution plan for parameters that passed in stored procedure first (parameters sniffing). For that values SQL engine can take decision not to use index. So to avoid it you can explicit set index usage.
Additional information about parameter sniffing you can find in this article (http://sqlperformance.com/2013/08/t-sql-queries/parameter-sniffing-embedding-and-the-recompile-options) and here (http://www.sommarskog.se/query-plan-mysteries.html)

Is gathering statistics necessary after dropping indexes and recreating them?

I use Oracle SQL, and I have one question. I have a table with indexes and it's statistics are gathered. I have a procedure that drops the indexes, inserts data into the table, and after that recreates the same indexes again. Do I need to gather statistics again after this procedure, or will the indexes be recognized anyway?
For gathering statistics i use:
EXEC dbms_stats.gather_table_stats(''MIGBUFFER'','''||table_name||''',cascade=>TRUE);
No. There is no need to gather index statistics immediately after index creation, since Oracle automatically gathers stats for indexes at creation time.
From documentation,
Oracle Database now automatically collects statistics during index
creation and rebuild.
I think it was way back in earlier releases, when you could use COMPUTE STATISTICS clause to start or stop the collection of statistics on an index. But, now this clause has been deprecated. Oracle Database now automatically collects statistics during index creation and rebuild. This clause is supported for backward compatibility and will not cause errors.

Non Clustered Index is not visible in Execution plan

I have implemented SQL Server's Change Data Capture feature in my database. When you enable CDC in your database , sql server will create some system tables for you like : cdc.dbo_Person_CT for tracking the changes you have in main Person table . I am using cdc.dbo_Person_CT table and i have applied Non-Clustered index on a column and i am using that column in select statement.
But when i see execution plan for my table ,it doesn't show Non-Clustered index ?? why
We would have to see the query and the index details but I would guess that the query is returning so many rows or that the index is not exclusive enough so the query analyzer decided to use a scan instead.

MySQL trigger in order to cache results?

I have a query that takes about a second to execute pre-cache. Post-cache is fine. Here's a description of the problem: MySQL: nested set is slow?
If I can't get a solution for my problem, would creating a trigger to loop through and execute all the possible queries that table might have to do (i.e. if there are 100 records on that table, it would execute 100 queries) be a good idea? This way, when my application does execute such a query, I can depend on cached results.
It feels like a bad solution, but I really can't afford a 1 second response time from that query.
Since you are using a MyISAM table, you can try preload the table indexes into the key cache.
http://dev.mysql.com/doc/refman/5.0/en/cache-index.html
http://dev.mysql.com/doc/refman/5.0/en/load-index.html

SQL Server Table Synonyms with Indexes

I have multiple databases on a single instance of SQL Server 2005. I've created a synonym on one database to access a table on another database and when writing my queries, I'd like to utilize a specific index, however, when evaluating the execution plan, it doesn't appear to use it. If I write the query to access the database explicitly, it works, but I can't seem to get it to work using a synonym. For example:
select *
from testdb..testtable with (index(testindex))
|--Nested Loops(Inner Join, OUTER REFERENCES:([testdb].[dbo].[testtable].[id]))
|--Index Scan(OBJECT:([testdb].[dbo].[testtable].[testindex]))
|--Clustered Index Seek(OBJECT:([testdb].[dbo].[testtable].[PK_testtable]), SEEK:([testdb].[dbo].[testtable].[id]=[testdb].[dbo].[testtable].[id]) LOOKUP ORDERED FORWARD)
does not yield the same execution plan as
select *
from testdb_synonym with (index(testindex))
|--Clustered Index Scan(OBJECT:([testdb].[dbo].[testtable].[PK_testtable]))
Is this a limitation with Synonyms or is there something specific I need to do to get this to work?
This is a bug that Microsoft have fixed: see MS KB 963684
In Microsoft SQL Server 2005, you
create a synonym for a table. You run
a query against the synonym. The query
uses the INDEX optimizer hint to force
an index. If you examine the execution
plan that is generated for the query,
you may find the execution plan does
not use the forced index.
I tested the same thing and it seems that the query optimizer ignores that hint when done via a synonym. The details are I did a select * against an arbitrary table with an index hint to use a non-clustered index. Without the synonym, it does a bookmark lookup/nested loop join. With it, it does a table scan. Since there are no options on the create synonym syntax, I can only assume that the index hint is ignored. No details in BOL as to why. I would chalk it up as a "feature".
WITH INDEX hints seems to be ignored for synonyms.
CREATE SYNONYM syn_master FOR master
SELECT *
FROM syn_master WITH (INDEX (wow_i_can_write_everything_here))
compiles and runs allright despite the fact I don't have an index named wow_i_can_write_everything_here in my schema.
Do you need the hint in your case? MS recommendations is to avoid index hints if it is possible due to the fact that may invalidate a more optimized plan. Even if it is optimized today it may be inefficiens tomorrow due to data load etc.
I tried to use a synonym without the hint in SQL server 2008 and got the same execution plan with the synonym as with the fully qualified name (database.schema.table).
I even tried to use the synonym with an index hint and successfully forced a non clustered index seek (and a key lookup to get the rest of the data), and i get the same execution plan with fully qualified name.
Are your statisitics updated? Do you have a selective index or does SQL server think it is more efficient to use a table scan.