Sybase CURSOR UPDATE extremeley slow / locking up
-
26-09-2019 - |
Question
I have a temp table with 13,000 rows. Most of the rows have a numeric price (100) but some are quoted in 32nds, i.e. 100-30 = 100 + 30/32 = 100.9375. (Some even have fractions of a 32th)
I am opening a cursor FOR UPDATE and iterating over the temp table. It takes so long to execute, I am not even sure it is working (my DBA says the exec plan looks 'strange')
Can anyone suggest why this is so ridiculously slow?
Better still, could anyone suggest a better alternative? I have control over how the temp table is created, but I don't fancy trying to compact the logic for 100-30 to 100.9375 into a single update statement.
I'd like to write a function to do this, but as far as I can tell, I have to install Java to enable UDFs?!
Lastly, any idea why Sybase is such an awful, primitive database even at version 12?
My stored proc:
DECLARE cur CURSOR FOR SELECT ticket_no, price_st, price, cur FROM #t FOR UPDATE OF price
DECLARE
@ticket_no INT,
@price_st VARCHAR(20),
@price FLOAT,
@int FLOAT,
@32s FLOAT,
@frac VARCHAR(6),
@num FLOAT,
@denom FLOAT
OPEN cur
FETCH cur INTO @ticket_no, @price_st
WHILE (@@SQLSTATUS != 2)
BEGIN
IF isnumeric(@price_st) = 1
BEGIN
SELECT @price = convert(FLOAT, @price_st)
END
ELSE
BEGIN
-- Convert a price like '99-22 3/4' to
-- 99 + (22/32) + (3/4 * 1/32)
SELECT @int = convert(FLOAT, substring(@price_st, 1, charindex('-', @price_st)-1))
SELECT @32s = convert(FLOAT, substring(@price_st, charindex('-', @price_st)+1, 2))
SELECT @frac = substring(@price_st, charindex(' ', @price_st)+1, 10)
SELECT @num = convert(FLOAT, substring(@frac, 1, charindex('/', @frac)-1))
SELECT @denom = convert(FLOAT, substring(@frac, charindex('/', @frac)+1, 3))
SELECT @price = @int + (@32s / 32) + (@num / (@denom * 32))
END
UPDATE #t SET price = @price WHERE CURRENT OF cur
FETCH cur INTO @ticket_no, @price_st
END
CLOSE cur
DEALLOCATE cur
Solution
Ah! I had a column in the table, with the same name as the cursor:
DECLARE cur CURSOR FOR SELECT ticket_no, price_st, price, cur FROM #t FOR UPDATE OF price
^ ^
This seems to put the Sybase server into a tailspin...
OTHER TIPS
Cursors in Sybase are slower than SET based operations. Despite your reluctance I doubt you will do better than putting all the logic into one Update
statement as below.
UPDATE #t
SET price =
CASE
WHEN isnumeric(price_st) = 1
THEN CONVERT(FLOAT, price_st)
ELSE
CONVERT(FLOAT, substring(price_st, 1, charindex('-', price_st)-1)) +
(CONVERT(FLOAT, substring(price_st, charindex('-', price_st)+1, 2)) / 32) +
(CONVERT(FLOAT, substring(substring(price_st, charindex(' ', price_st)+1, 10), 1, charindex('/', substring(price_st, charindex(' ', price_st)+1, 10))-1)) /
(CONVERT(FLOAT, substring(substring(price_st, charindex(' ', price_st)+1, 10), charindex('/', substring(price_st, charindex(' ', price_st)+1, 10))+1, 3)) * 32))
END