We currently have a LOGS TABLE divided with multiple logbooks numbers (column XLOG), and accessed within a limited time range.
The table is declared with a clustered ‘natural’ primary key, where XLOG is logbook identifier, XDATE is the timestamp, and XHW and XCELL are hardware identifiers ensuring unicity of log events :
CREATE TABLE [dbo].[LOGS](
[XDATE] [datetime] NOT NULL,
[XHW] [nvarchar](3) NOT NULL,
[XCELL] [nvarchar](3) NOT NULL,
[XALIAS] [nvarchar](255) NULL,
[XMESSAGE] [nvarchar](255) NULL,
[XLOG] [int] NOT NULL,
CONSTRAINT [PK_LOG] PRIMARY KEY CLUSTERED ([XLOG] ASC,[XDATE] ASC,[XHW] ASC,[XCELL] ASC)
The problem is a horrible execution plan occuring when accessing multiple logbooks with the same query (e.g. XLOG = 1 OR XLOG = 1002 in the sample query below), request #1 :
SELECT TOP 100 XDATE, XHW, XCELL, XMESSAGE, XLOG FROM LOGS
WHERE XDATE > '2012-06-12T00:00:00' AND XDATE < '2012-07-13T08:29:03.250'
AND (XLOG = 1 OR XLOG = 1002)
ORDER BY XDATE DESC, XLOG DESC
Edit: the 100 rows needed are not only from logbook #1, but from both logbooks, mixed, date ordered. That is what both queries return.
Statistics were updated before the tests.
The actual execution plan basically uses clustered index seek to fetch million rows of data with a predicate on XLOG and XDATE, (where it might only fetch 100 first/last rows since we have XLOG= and we TOP order by XDATE) 
The details of the clustered index seek operation : 
The expected execution plan is 
I tried to rewrite the query, but could not find another way except with UNION ALL. The resulting query returns the same results (with a correct plan !) but it feels over-complicated (and cannot be adapted with a JOIN on XLOG, but that is not the question) request #2 :
WITH A AS (SELECT TOP 100 XDATE, XHW, XCELL, XMESSAGE, XLOG FROM LOGS
WHERE XDATE > '2012-06-12T00:00:00' AND XDATE < '2012-07-13T08:29:03.250'
AND XLOG = 1
ORDER BY XDATE DESC),
B AS (SELECT TOP 100 XDATE, XHW, XCELL, XMESSAGE, XLOG FROM LOGS
WHERE XDATE > '2012-06-12T00:00:00' AND XDATE < '2012-07-13T08:29:03.250'
AND XLOG = 1002
ORDER BY XDATE DESC)
SELECT TOP 100 * FROM (
SELECT * FROM A
UNION ALL
SELECT * FROM B
) A
ORDER BY XDATE DESC, XLOG DESC
Question: What is wrong with request #1 ? how can it be rewritten/modified, to take the ‘TOP’ into account before attempting to sort millions of rows ? is another index, HINT, or some extra statistics needed to solve the problem ? am-I obliged to rewrite the queries like the request #2 ?
Edit: Quantitatively this table holds a dozen of logbooks, some have as few as one event per month, when others have millions of events per month.
This kind of query is the most used against this table (there are other variants with extra filters but they are not relevant for this problem — except for complexity when using request #2).
Edit #2: I tried the solution of changing the clustered index to (XDATE,XLOG,…) instead of (XLOG,XDATE,…) — nb: This composite primary key was designed this way because of the low selectivity of the column XLOG.
I tested this query on a copy of the production database, against a logbook with only a thousand of rows : the query plan generates LOTS OF I/O (it filters out only a few rows from that XLOG=12 out of a wide range of XDATEs). So this particular solution is not ok.
SELECT TOP 100 XDATE, XHW, XCELL, XMESSAGE, XLOG FROM LOGS
WHERE XDATE > '2012-06-12T00:00:00' AND XDATE < '2012-07-13T08:29:03.250'
AND (XLOG = 12 AND XALIAS LIKE 'KEYWORD%' )
ORDER BY XDATE DESC, XLOG DESC, XHW DESC, XCELL DESC

PS: By the way, we have the same behaviour with PostgreSQL 9.1 – so it is not database related, more probably a wrong query or a wrong table design.
The issue is that the database does not know that the first 100 rows you want are all XLOG=1 so has to get all the possible XLOGS and then sort to find the first 100.
In your second case you have given more information or cut down the rows selected so the optimizer can just use the index for sorting.
Another way is to make the clustered index on XDATE DESC, XLOG DESC then the optimizer will know it does not have to sort and make the primary key a hash or other index. This ony makes sense if this query is the one most used.