SQL is slow

  • I have a stored proc that takes about 15-17 seconds to run. I would like to get it to run in 5 seconds or less. Here are the basic steps:

    1) Create a temp table

    2) Create an index on temp table

    3) Insert into temp table with a select

    4) Insert into temp table with a select again

    5) Then there are 13 additional update statements to the temp table to fill in all of the appropriate values

    I know this doesn't provide you with a lot of details but are there any thoughts you give from a general perspective in which I should condsider?

    If I run steps 1-4 w/out the updates, it takes about 3 seconds.

  • Create a copy of the procedure and do timestamp wrappers around each of the updates. Find out where the pain in time is. Then start pulling out execution plans to find the bottleneck.


    - Craig Farrell

    Never stop learning, even if it hurts. Ego bruises are practically mandatory as you learn unless you've never risked enough to make a mistake.

    For better assistance in answering your questions[/url] | Forum Netiquette
    For index/tuning help, follow these directions.[/url] |Tally Tables[/url]

    Twitter: @AnyWayDBA

  • OK - that's a good start - thank you.

  • Craig Farrell (9/30/2010)


    Create a copy of the procedure and do timestamp wrappers around each of the updates. Find out where the pain in time is. Then start pulling out execution plans to find the bottleneck.

    After the first 2 insert statements I did a start and end date before and after each update. Here are my results. The far right column are the millisecond differences. This whole query took 17 seconds. I'm actually working on a test DB but the normal DB takes 40 seconds for this to run. Rows 4 and 5 take the longest but I'm nut sure how to optiize it because it is doing a bunch of updates based on values from the temp table.

    12010-09-30 12:39:58.2632010-09-30 12:39:59.3001036

    22010-09-30 12:39:59.3032010-09-30 12:40:00.097793

    32010-09-30 12:40:00.0972010-09-30 12:40:00.820723

    42010-09-30 12:40:00.8202010-09-30 12:40:02.9232103

    52010-09-30 12:40:02.9272010-09-30 12:40:05.4532526

    62010-09-30 12:40:05.4532010-09-30 12:40:06.103650

    72010-09-30 12:40:06.1072010-09-30 12:40:06.667560

    82010-09-30 12:40:06.6672010-09-30 12:40:07.450783

    92010-09-30 12:40:07.4502010-09-30 12:40:07.790340

    a2010-09-30 12:40:07.7902010-09-30 12:40:08.480690

    b2010-09-30 12:40:08.4802010-09-30 12:40:09.183703

    c2010-09-30 12:40:09.1832010-09-30 12:40:09.497313

    d2010-09-30 12:40:09.4972010-09-30 12:40:10.130633

    e2010-09-30 12:40:10.1302010-09-30 12:40:10.20373

  • For example, here is one of the longer updates - is there a better way to do this?

    UPDATE #temp_table

    set clm_loc_city = (select loc_city

    from LOCATION_TABLE

    where #temp_table.car_init = LOCATION_TABLE.car_init

    and #temp_table.car_no = LOCATION_TABLE.car_no),

    clm_loc_state = (select loc_state

    from LOCATION_TABLE

    where #temp_table.car_init = LOCATION_TABLE.car_init

    and #temp_table.car_no = LOCATION_TABLE.car_no),

    clm_sight_code = (select sight_code

    from LOCATION_TABLE

    where #temp_table.car_init = LOCATION_TABLE.car_init

    and #temp_table.car_no = LOCATION_TABLE.car_no),

    clm_date_time = (select clm_date_time

    from LOCATION_TABLE

    where #temp_table.car_init = LOCATION_TABLE.car_init

    and #temp_table.car_no = LOCATION_TABLE.car_no),

    clm_le = (select le

    from LOCATION_TABLE

    where #temp_table.car_init = LOCATION_TABLE.car_init

    and #temp_table.car_no = LOCATION_TABLE.car_no),

    clm_road = (select road

    from LOCATION_TABLE

    where #temp_table.car_init = LOCATION_TABLE.car_init

    and #temp_table.car_no = LOCATION_TABLE.car_no),

    clm_trn_jct = (select trn_jct

    from LOCATION_TABLE

    where #temp_table.car_init = LOCATION_TABLE.car_init

    and #temp_table.car_no = LOCATION_TABLE.car_no),

    clm_dest_city = (select dest_city

    from LOCATION_TABLE

    where #temp_table.car_init = LOCATION_TABLE.car_init

    and #temp_table.car_no = LOCATION_TABLE.car_no),

    clm_dest_state = (select dest_state

    from LOCATION_TABLE

    where #temp_table.car_init = LOCATION_TABLE.car_init

    and #temp_table.car_no = LOCATION_TABLE.car_no),

    days_at_location = (select DATEDIFF(dd,LOCATION_TABLE.clm_date_time,getdate())

    from LOCATION_TABLE

    where #temp_table.car_init = LOCATION_TABLE.car_init

    and #temp_table.car_no = LOCATION_TABLE.car_no)

  • Expand this code to each field. You're running subqueries for each line, that's going to hurt.

    UPDATE tt

    SETclm_loc_city = lt.loc_city,

    clm_loc_state = lt.loc_state

    -- ... keep going on

    FROM

    #temp_table AS tt

    JOIN

    LOCATION_TABLE as lt

    ONtt.car_init = lt.car_init

    AND tt.car_no = lt.car_no


    - Craig Farrell

    Never stop learning, even if it hurts. Ego bruises are practically mandatory as you learn unless you've never risked enough to make a mistake.

    For better assistance in answering your questions[/url] | Forum Netiquette
    For index/tuning help, follow these directions.[/url] |Tally Tables[/url]

    Twitter: @AnyWayDBA

  • That update looks very RBAR to me (google RBAR if you are not familiar with the term).

    Not knowing much about the guts of what you are actually trying to accomplish, I would initially say you will probably find your biggest gains by converting these updates into more set-based solutions. Familiarize yourself with set-based solutions vs programmatic solutions, because there are distinct differences.

    For example, instead of saying UPDATE <temptab> SET <col1> = (SELECT col1 FROM <realtab> WHERE <temptab>.id = <realtab>.id), try something like this -

    SELECT <temptab>.id, <realtab>.<col1> INTO #temp2 FROM <temptab>, <realtab> WHERE ....

    Then, you are creating the SAME result set by doing SELECT/JOIN in one operation instead of making sql server do work for every row as it would with your update.

  • Craig's sql statement is cleaner - do something like what he wrote.

  • you are trying to update the LOCATION_TABLE columns into #temp_tables column. am i right.

    if that is true you don't need to use the co-related sql statement on this cause.

    you can simply use simple inner join because the outer query and the co-related query is using/referring the same column to match both the tables.

    let me know we are on the same page.

  • I couldn't agree more with Joe on this one. You're really bashing your fingers with a hammer.

    While there are situations where breaking up statements and using a temp table can make things run faster, most of the time, the real value is in using all the tools at your disposal to create a set based query to do the update in a single pass.

    In general, instead of working on the UPDATE or INSERT queries, I work on defining a SELECT statement that gets me exactly the data I want. From there, I can determine if I need to then break it up into temp tables or not (and the answer 99/100 is Not).

    "The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
    - Theodore Roosevelt

    Author of:
    SQL Server Execution Plans
    SQL Server Query Performance Tuning

  • Here's one that is taking a while:

    UPDATE #temp_trips

    set tcomment_type = (SELECT RT_TRIP_COMMENTS.comment_type

    FROM RT_TRIP_COMMENTS

    where #temp_trips.car_init = RT_TRIP_COMMENTS.car_init

    and #temp_trips.car_no = RT_TRIP_COMMENTS.car_no

    and #temp_trips.ship_date_time = RT_TRIP_COMMENTS.ship_date_time

    and (RT_TRIP_COMMENTS.comment_type <> 'EX' or RT_TRIP_COMMENTS.comment_type is null)

    and comment_date = (SELECT max(comment_date)

    FROM RT_TRIP_COMMENTS

    where #temp_trips.car_init = RT_TRIP_COMMENTS.car_init

    and #temp_trips.car_no = RT_TRIP_COMMENTS.car_no

    and #temp_trips.ship_date_time = RT_TRIP_COMMENTS.ship_date_time

    and (RT_TRIP_COMMENTS.comment_type <> 'EX' or RT_TRIP_COMMENTS.comment_type is null))

    GROUP BY RT_TRIP_COMMENTS.car_init, RT_TRIP_COMMENTS.car_no, RT_TRIP_COMMENTS.ship_date_time, RT_TRIP_COMMENTS.comment_type

    )

  • Rog Saber (9/30/2010)


    Here's one that is taking a while:

    [Snip beginning of statement]

    and (RT_TRIP_COMMENTS.comment_type <> 'EX' or RT_TRIP_COMMENTS.comment_type is null)

    The <> here is probably blowing up an index seek. Need to do an index review.

    and comment_date = (SELECT max(comment_date)

    FROM RT_TRIP_COMMENTS

    where #temp_trips.car_init = RT_TRIP_COMMENTS.car_init

    and #temp_trips.car_no = RT_TRIP_COMMENTS.car_no

    and #temp_trips.ship_date_time = RT_TRIP_COMMENTS.ship_date_time

    and (RT_TRIP_COMMENTS.comment_type <> 'EX' or RT_TRIP_COMMENTS.comment_type is null))

    GROUP BY RT_TRIP_COMMENTS.car_init, RT_TRIP_COMMENTS.car_no, RT_TRIP_COMMENTS.ship_date_time, RT_TRIP_COMMENTS.comment_type

    )

    To paraphrase Mr. Jeff Moden: Welcome to RBAR. Row by agonizing Row. You would probably be better off with the 'group by' in a sub query, then reconnecting back in on four fields, rather then have the 3 fields and then a select statement that runs a group by per row. Explore using an exists clause, or a straight join, off your #table to build the subquery to find the max date.


    - Craig Farrell

    Never stop learning, even if it hurts. Ego bruises are practically mandatory as you learn unless you've never risked enough to make a mistake.

    For better assistance in answering your questions[/url] | Forum Netiquette
    For index/tuning help, follow these directions.[/url] |Tally Tables[/url]

    Twitter: @AnyWayDBA

Viewing 12 posts - 1 through 11 (of 11 total)

You must be logged in to reply to this topic. Login to reply