August 12, 2013 at 7:41 am
ChrisM@Work (8/12/2013)
This, I think, would make a reasonable test query:
SELECT
jt.job,jt.suffix, jt.oper_num, jt.trans_num, jt.emp_num,
x.oper_num, x.trans_num, x.emp_num,
jt2.trans_num
FROM jobtran jt (NOLOCK)
OUTER APPLY (
SELECT TOP 1
jtx.emp_num, jtx.oper_num, jtx.trans_num
FROM jobtran jtx(NOLOCK)
WHERE jtx.job = jt.job
ANDjtx.suffix = jt.suffix
AND jtx.oper_num >= jt.oper_num
ANDjtx.emp_num IS NOT NULL
AND jtx.trans_num < jt.trans_num
ORDER BY jtx.oper_num, jtx.trans_num DESC
) x
OUTER APPLY ( -- Set up time only backflushed for first booking,
SELECT -- so check that no previous booking exists for op.
trans_num = MIN(trans_num)
FROM jobtran j (NOLOCK)
WHERE j.job = jt.job
AND j.suffix = jt.suffix
AND j.oper_num = jt.oper_num
) jt2
WHERE jt.trans_class = 'J'
ANDISNULL(jt.posted,0) = 1 -- Only show posted transactions
So what you're doing here is testing for the result of different scenarios? I like the way I can see how the emp_num can be traced through the different scenarios.
I'd tried using OUTER APPLY before posting and found that (with my statement) that there was no performance gain.
August 12, 2013 at 7:42 am
ChrisM@Work (8/12/2013)
It is referenced:
CASE -- All std time captured on Move*, as this is where quantity is recorded
-- where Move trans types don't exist, qty is recorded on other trans types (e.g C)
WHEN ISNULL(jt.qty_moved,0) <> 0
AND jt2.trans_num IS NULL
Doh! Sorry!
August 12, 2013 at 8:20 am
Try this index, Mike:
CREATE INDEX ix_Test ON Jobtran (oper_num, trans_num DESC, job, suffix) INCLUDE (emp_num)
Edit: CREATE INDEX ix_New ON Jobtran (job, suffix, oper_num, trans_num DESC) INCLUDE (emp_num)
For fast, accurate and documented assistance in answering your questions, please read this article.
Understanding and using APPLY, (I) and (II) Paul White
Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden
August 12, 2013 at 9:04 am
The first suggested index made little to no difference (probably why you edited the post!) and so I removed from my DB after testing.
The second suggested index halved the running time. This is without the other previously suggested indexes in play. I don't know if this was intentional or not but the second one is also the same as you suggested earlier implying that your first instincts were correct.
With this second query in place my 'problem' query example is now running in under 30 seconds compared to the original posted 50+ seconds. Even better, the 'full' query is now running in under 60 seconds when previously it was taking nearly 2. Quite a result thanks to you.
I really appreciate you taking the time to help me in this matter. In deciding on the most efficient index to build did you look at the fields used in the query and include those in a query, or was there some other clue to help you have that suggestion?
August 12, 2013 at 9:36 am
Picking the right columns to use for a covering index is mostly straightforward. List all of the columns used in the (sub)query. If the column is used as a filter or a join then it's probably a key column, otherwise it's an INCLUDE column. Getting the order of the columns correct in the key column list can be a little hit or miss (see today's ssc headlines). What you're looking for in the plan is to see as many as possible of your key columns used in the seek predicate and as few as possible remaining in the residual predicate, and this often takes a little experimentation.
The new index is designed to help the emp_num subquery. It supports seeks albeit with a residual predicate and the data comes out already sorted for the TOP operator i.e. in the same order as the sort operator in the original query, which, in the test harness and without the index, appears as about 95% of the total query cost.
In the little test harness, the new index is also used by the second subquery although with a less dramatic effect.
I'm sure more improvements are possible if you wish to pursue it.
For fast, accurate and documented assistance in answering your questions, please read this article.
Understanding and using APPLY, (I) and (II) Paul White
Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden
August 13, 2013 at 12:48 am
Thank you for your help and for the insight on picking the correct fields for new indexes. (thinking of old proverb about fishing and eating)
I like learning and hope that this will bring untold benefits to my administration of my servers.
All I have to do now is remember that indexes are not always the solution to the problem!
Viewing 6 posts - 16 through 20 (of 20 total)
You must be logged in to reply to this topic. Login to reply