Bad query plan only on first execution, not in SSMS
When application is run for the first time of day,then it is usually slow,so problem may be in Middleware logic also.

Like you said you are using Dataset,if your were using Generic collection like LIST and populate them with SqlDataReader,then you can see the performance improvement your self.

Second thing is How you are using those 2 ResultSet ?Are the subject to further filter between datatable. ?

As far as your query is visible, I see that you are querying Order Table twice using same predicate and Order by clause

your query can be rewritten like this,

Create TABLE #tempOrder(all required columns)
insert into #tempOrder
SELECT TOP (20) bunch of configurable columns, xml blob of customer preferences, ...
FROM ORDERS
INNER JOIN CUSTOMERS ON CUSTOMERS.ID = ORDERS.CUSTOMERID 
INNER JOIN CUST_PREFS ON CUSTOMERS.ID = CUST_PREFS.CUSTOMERID
WHERE ORDERS.DATE BETWEEN @from and @to
ORDER BY ORDERS.DATE

SELECT bunch of configurable columns, xml blob of customer preferences, ...
FROM
#tempOrder ORDERS
INNER JOIN
    (SELECT sums, avgs, etc FROM ORDERDETAILS
     GROUP BY ORDERDETAILS.ORDERID) orderavg on orderavg.ORDERID = ORDERS.ORDERID
... whatever other joins needed based on configuration ...



SELECT ORDERID, orderdetails
FROM
    (SELECT ORDERID
     FROM #tempOrder ORDERS
INNER JOIN ORDERDETAILS ON ORDERDETAILS.ORDERID = ORDERS.ORDERID

Create Non Clustered index on ORDERS(DATE)


There is no point in creating index on #tempOrder since it will contain only 20 records always(Top 20 indicate) 


  bunch of configurable columns


It means that query must be dynamic so it all depend upon your real query.

Use SET NOCOUNT ON