Question: For a while now we've been having anecdotal slowness on our newly-minted (VMWare-based) SQL Server 2005 database servers. Recently the problem has come to a head and I've started looking for the root cause of the issue. 

Here's the weird part: on the stored procedure that I'm using as a performance test case, I get a 30x difference in the execution speed depending on which DB server I run it on. This is using the same database (mdf) and log (ldf) files, detached, copied, and reattached from the slow server to the fast one. This doesn't appear to be a (virtualized) hardware issue: he *slow* server has 4x the CPU capacity and 2x the memory as the *fast* one. 

As best as I can tell, the problem lies in the environment/configuration of the servers (either operating system or SQL Server installation). However, I've checked a bunch of variables (SQL Server config options, running services, disk fragmentation) and found nothing that has made a difference in testing.

What things should I be looking at? What tools can I use to investigate why this is happening?

Answer: 
Blindly checking variables and settings won't get you very far. You need to approach this methodically.

1. Are the two procedures executed the same way? Namely, is the plan different? A quick check is to `SET STATISTICS IO ON` and run the two cases. Is the number of logical-reads the same? Is the number of physical-reads the same? Is the number of writes the same? Differences in logical-reads or writes would indicate a different plan. Differences in physical-reads (while logical-reads is similar) indicate cache and memory problems. If the plans are different, you need to further investigate what is different in the actual execution plan. Does one plan uses a different degree of parallelism? Does one use different join types? Different access paths?
2. If the plans are similar yet the execution is still different, and you cannot blame the IO subsystem, then you need to check contention. Use `SET STATISTICS TIME ON` and compare the elapsed time and worker time in the two cases. Similar worker time but different elapsed time indicate that there is more waiting in one case. Use the wait\_type and wait\_resource info in sys.dm\_exec\_requests to identify the cause of contention.

The methodology of investigation is discussed in more detail in the [Waits and Queues whitepaper](http://sqlcat.com/whitepapers/archive/2007/11/19/sql-server-2005-waits-and-queues.aspx).
Run [SQL Server Profiler](http://msdn.microsoft.com/en-us/library/ms187929.aspx) to gather information about running processes within SQL Server. This is probably the best start. This will give you a good idea of the things that are consuming a lot of resources.

If you still have issues after Indexing / Rebuilding Indexes, or rewriting queries, then the next step would be to run PerfMon.