Can some clever spark out there explain why, when I have a sorted stream (eg. using clustered index) which I then perform a hash join, result in an unordered stream? In the example below, basket table and basket_item table both have clustered indexed sorted by basket_id asc. without the inner hash join between product and basket, the query is happy merge joining without requiring a sort. As soon as I put the the hash join in it performs the hash join on the sorted stream (basket_item) - but then has to sort the resultant stream before merge joining to the basket table. I have over 800M rows in the basket table - so this is not a good plan! The query below is a little contrived to demonstrate the problem - my "real" query does not involve taking the min(major_department_code) - but if anyone has any idea how to remove this redundant sort, then please let me know. I have considered that it may have been to do with a parallel process, but seting MAXDOP to 1 does not resolve the query either. I'm sure there may be a technical reason for this, but the hash join process is described as "use each row from the top input to build a hash table, and each row in the bottom to probe into the hash table, outputing all matched results" - my "top" input is the product table - and my bottom query is the basket_item - so why, if the bottom is sorted, would it want to re-sort itself after the hash join? select bb.basket_id , bi.min_mdc from mart.basket bb left merge join ( select a.basket_id , min_mdc = min(p.major_department_code) from mart.product p inner hash join mart.basket_item a on p.product_id = a.product_id group by a.basket_id ) bi on bi.basket_id = bb.basket_id
"if the bottom is sorted, why would it want to re-sort itself after the hash join" strangely the optimizer doesn't think so. Look at the inputs to the hash join, the optimizer has the Ordered property set to False even though they are both clustered index scans. If I were to speculate, I would say this is because the hash of the key is not ordered the same as the key. Change this to merge join and presto, it is now ordered...I guess to answer your question, to get rid of the sort, change both joins to merge or both joins to hash (but then you will have to sort later anyway). If you post your actual query we may be able help to optimize it.
As far as I understand it, by applying a hash function to your data and thus pushing it into hash buckets, you are removing any sort order that was previously present. The Query Optimiser (QO) then no longer considers the data sorted and has to re-sort after the hash join. This begs the question - Why are you forcing a hash join at all? Query hints should be rarely used (extreme edge cases in my experience), where you *really* know better than the QO. You say that you are running a join on two suitably sorted sets of data with large volumes - a MERGE JOIN is the best join type for this operation. It is not surprising to see the QO making this decision. The only time I have prescribed the use of join hints was when an ad-hoc query was coming into a system where the normal query plan would be incorrect through the parameters being used. Forcing a certain join type and marking the plan for one-time-use was the way to go. In your scenario, I would remove all join hints and let SQL Server decide what is best by running through the schema meta-data and statistics at hand.
The data returned by the hash join is not guaranteed to be in any particular order. As I understand it, the hash join has the following features that may explain your observed behaviour: * memory is pre-allocated based on estimated rowcounts * overspill goes into the TempDB If you're running through an 850M row record set, then the data is certain to be dumped to TempDB, where it is treated just like any other table. And data returned from any table is **not guaranteed to be in any particular order.**