У меня есть метод веб-службы Java getCardInformation
, который получает данные из базы данных Oracle
, используя JDBC
. Около 300 звонков в секунду.
Java вызывает эту функцию pl / sql:
PROCEDURE GET_CARDS_BY_ID(p_card_id IN NUMBER
,o_result OUT VARCHAR2) IS
BEGIN
SELECT 'some data'
INTO o_result
FROM 'my complicated SQL' c
WHERE c.card_id = p_card_id;
END GET_CARDS_BY_ID;
Обычно SQL Select statement/procedure
возвращает результат в течение 30 мс, но иногда бывают случаи, когда требуется более 20 секунд, и все другие потоки (вызовы) ждут этого отложенного вызова.
Хотя эти вызовы не связаны друг с другом, они запускают один и тот же SQL Select statement
с разными входными параметрами.
Все параметры устанавливаются из Java с использованием bind variables
.
Во время задержки мы выбрали активные сеансы и получили множество курсора : контакт S wait на X
SELECT DISTINCT a.*, s.*
FROM V$ACTIVE_SESSION_HISTORY a
,v$sql s
WHERE a.sql_id = s.sql_id
AND blocking_session IS NOT NULL
AND a.sample_time > sysdate - 1
Мы решили проблему, добавив hint
к нашему Select
.
Мы думаем, что во время этой задержки Oracle пытается проанализировать Select Statement
и re для расчета плана, который требует некоторого времени. Все остальные вызовы, использующие тот же оператор, ожидают, пока Oracle завершит вычисление. Это причина задержки. Когда мы установили подсказку, мы сказали оракулу не делать никаких вычислений, поэтому задержки не было.
Но почему Oracle пытается пересчитать план?
Можно ли решить эту проблему без жесткого кодирования индекса?
Когда объем моих данных изменяется в базе данных, я не хочу менять свой код из-за этой подсказки.
Оператор SQL:
SELECT (nvl((SELECT SUM(amount)
FROM locks l
WHERE l.account = a.account),
0) - nvl((SELECT SUM(sl.amount)
FROM locks sl
,locks_2 m
WHERE sl.id = m.id
AND sl.account = a.account
AND m.text = '...'),
0)) / 100
,a.credit_limit / 100
,nvl((SELECT SUM(decode(ia.account,
ra.id,
ia.bal,
ceil(CASE
WHEN cc.ccy_num = '100' THEN
(SELECT ia.bal / r.ccy_rate
FROM my_ccy_rate r
WHERE r.ccy_num = a.account_ccy)
WHEN a.account_ccy = '100' THEN
(SELECT ia.bal * r.ccy_rate
FROM my_ccy_rates r
WHERE r.ccy_num = cc.ccy_num)
ELSE
(SELECT ia.bal * r.ccy_rate / c.ccy_rate + 15000
FROM my_ccy_rates r
,my_ccy_rates c
WHERE r.ccy_num = cc.ccy_num
AND c.ccy_num = a.account_ccy)
END)))
FROM my_v ia
,currency_codes cc
,my_table pe
WHERE ia.account = a.account_id
AND cc.ccy_alpha = ia.ccy),
0) / 100
,a.initial_amount / 100
,nvl((SELECT a.bonus_amount - nvl((SELECT SUM(sl.amount)
FROM locks sl
,locks_2 m
WHERE sl.id = m.id
AND sl.account_id = a.account_id
AND m.text = '...'),
0)
FROM my_table_1 ra
,my_accounts a
WHERE ra.centre_id = o_centre_id
AND ra.card_number = o_card
AND a.centre_id = ra.centre_id
AND a.account_id = ra.account_id),
0) / 100
INTO o_amt_1
,o_amt_2
,o_amt_3
,o_amt_4
,o_amt_5
FROM my_table_1 ra
,my_table_2 a
,my_table_3 p
WHERE ra.card_number = &card_number_input_parameter
AND a.account_id = ra.account_id;