Tell me more ×
Database Administrators Stack Exchange is a question and answer site for database professionals who wish to improve their database skills and learn from others in the community. It's 100% free, no registration required.

Let's say I have a single table

CREATE TABLE Ticket (
    TicketId int NOT NULL,
    InsertDateTime datetime NOT NULL,
    SiteId int NOT NULL,
    StatusId tinyint NOT NULL,
    AssignedId int NULL,
    ReportedById int NOT NULL,
    CategoryId int NULL
);

In this example TicketId is the Primary Key.

I want users to be able to create "partially ad-hoc" queries against this table. I say partially because a few parts of the query will always fixed:

  1. The query will always perform a range filter on an InsertDateTime
  2. The query will always ORDER BY InsertDateTime DESC
  3. The query will page results

The user can optionally filter on any of the other columns. They can filter on none, one, or many. And for each column the user may select from a set of values which will be applied as a disjunction. For example:

SELECT
    TicketId
FROM (
    SELECT
        TicketId,
        ROW_NUMBER() OVER(ORDER BY InsertDateTime DESC) as RowNum
    FROM Ticket
    WHERE InsertDateTime >= '2013-01-01' AND InsertDateTime < '2013-02-01'
      AND StatusId IN (1,2,3)
      AND (CategoryId IN (10,11) OR CategoryId IS NULL)
    ) _
WHERE RowNum BETWEEN 1 AND 100;

Now assume the table has 100,000,000 rows.

The best I can come up with is a covering index that includes each of the "optional" columns:

CREATE NONCLUSTERED INDEX IX_Ticket_Covering ON Ticket (
    InsertDateTime DESC
) INCLUDE (
    SiteId, StatusId, AssignedId, ReportedById, CategoryId
);

This gives me a query plan as follows:

  • SELECT
    • Filter
      • Top
        • Sequence Project (Compute Scalar)
          • Segment
            • Index Seek

It seems pretty good. About 80%-90% of the cost comes from the Index Seek operation, which is ideal.

Are there better strategies for implementing this kind of searching?

I don't necessarily want to offload the optional filtering to the client because in some cases the result set from the "fixed" part could be 100s or 1000s. The client would then also be responsible for sorting and paging which might too much work for the client.

share|improve this question
Would it be possible to place your subquery into a temp table or table variable and build that way? With my larger tables, I sometimes get stung by subqueries. Covering indexes only take you so far. – Valkyrie Feb 5 at 13:54
@Valkyrie that seems incredibly inefficient. Also consider that variants of this query (different parameters and different optional where clauses) will likely be executing several times a second all day long and need to return results on average in less than 100ms. We already do this, and it performs okay for now. I'm just looking for ideas on how to continue to improve performance for scalability. – Joseph Daigle Feb 6 at 12:47
How much do you care about using storage space? – Jon Seigel yesterday
@JonSeigel it depends on how much... but I want to see any suggestions – Joseph Daigle yesterday

1 Answer

If the clients are filtering in almost the same way over and over again you can create an index for those queries.

E.g. the client is filtering on SiteId and StatusId you can create an additional index:

CREATE NONCLUSTERED INDEX IX_Ticket_InsertDateTime_SiteId_StatusId ON Ticket     
(InsertDateTime DESC,
 SiteId [ASC/DESC],
 StatusId [ASC/DESC] ) 
 INCLUDE ( ... );

This way, most of the 'more common' queries could run fast.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.