How to assert that your SQL does not do full table scans

Thursday, March 25, 2010 3:18:00 PM (Romance Standard Time, UTC+01:00)

In database applications it is often important to ensure that your SQL uses indexes to avoid performance problems. Consider an SQL select statement like this

SELECT text FROM response WHERE questionId = 27 AND participantId = 38

If there is no index on response(questionId, participantId), the database needs to do a full table scan, and if the response table have a lot of rows, this will degrade performance. Such a performance problem might only be observed during testing on large amounts of data, which is not typically something a developer will do before every commit.

It would be useful to be able to detect this kind of problem much earlier, preferably during unit testing. Here I will describe one way to do this using Microsoft SQL Server and .NET:

SQL Server makes a lot of information accessible through performance counters, and one of those performance counters is incremented every time SQL Server does a full table scan. Utilizing that information, we can write a unit test that verifies that indexes are properly in place by asserting that the number of full table scans performed by a piece of code is equal to zero:

using(new AssertSqlFullScanCount(0))
{

var
responses = Response.GetResponses(q, p);
Assert.That(responses, ...);
}

This code uses the following helper class:

public class AssertSqlFullScanCount : IDisposable
{
private
int expected;
private long actual;
private PerformanceCounter fullScans;
public AssertSqlFullScanCount(int expected)
{
this.expected = expected;
this.fullScans = new PerformanceCounter(
"MSSQL$SQLEXPRESS:Access Methods",
"Full Scans/sec");
this.actual = fullScans.RawValue;
}

public
void Dispose()
{
actual = fullScans.RawValue - actual;

Assert.That(actual, Is.EqualTo(expected));
}
}

Do you consider this kind of performance unit testing useful? How would you implement this kind of tests with Oracle

By Lars Thorup