Запрос выполняется в 4800 раз дольше при запуске из программы на C ++, чем из SQL Plus - PullRequest
7 голосов
/ 29 ноября 2011

У нас серьезная проблема с запросом, который не поддается объяснению.В SQL-plus или TOAD он выполняется за 1/2 секунды, но при запуске из программы на C ++ через распределенную транзакцию это занимает 41 минуту.До этой недели это выполнялось 10 000 раз из кода C ++ всего за секунду.

Ничего не изменилось ни в БД, ни в коде, ни на серверах W2k, выполняющих код.

при запуске изкод имеет очень высокую скорость последовательного чтения файла БД более 1 000 000

, когда точно такой же оператор запускается из SQL, плюс последовательное чтение файла БД составляет 8

Так что тот же оператор выполняет в 100 000 раз больше работы, когдавыполнить через код и DT, чем из sqlplus.

мы сделали следующий запрос, чтобы найти, какие блоки читаются SELECT p1 "file #", p2 "block #", p3 "class #" FROM v $ session_wait WHEREevent = 'последовательное чтение файла db'

, и они являются таблицами, используемыми в запросе.Он читает таблицы снова и снова, но план объяснения указывает, что должны быть прочитаны только 8 блоков

обе таблицы имеют размер ~ 10 гигабайт

вот устав и план объяснения

SELECT COUNT (*)
  FROM student st, testinstance ti
 WHERE st.dataset_id = :b2
   AND st.student_id = ti.student_id
   AND ti.testinstance_id > :b1
   AND NOT EXISTS (
          SELECT 1
            FROM programscoringexclusion ex
           WHERE ex.program_id = wfgeneral.getprogramid (:b3)
             AND ex.testfamily_id = ti.testfamily_id
             AND NVL (ex.test_level, NVL (ti.test_level, '*')) =
                                                      NVL (ti.test_level, '*')
             AND NVL (ex.battery, NVL (ti.battery, '*')) =
                                                         NVL (ti.battery, '*')
             AND NVL (ex.form, NVL (ti.form, '*')) = NVL (ti.form, '*'))

             Plan
SELECT STATEMENT  CHOOSECost: 2                     
    9 SORT AGGREGATE  Bytes: 43  Cardinality: 1                 
        8 FILTER            
            5 NESTED LOOPS  Cost: 2  Bytes: 43  Cardinality: 1          
                2 TABLE ACCESS BY INDEX ROWID TABLE BBOX.TESTINSTANCE Cost: 1  Bytes: 32  Cardinality: 1    
                    1 INDEX RANGE SCAN INDEX (UNIQUE) BBOX.XXPK0TESTINSTANCE Cost: 1  Cardinality: 1  
                4 TABLE ACCESS BY INDEX ROWID TABLE BBOX.STUDENT Cost: 1  Bytes: 11  Cardinality: 1     
                    3 INDEX UNIQUE SCAN INDEX (UNIQUE) BBOX.XXPK0STUDENT Cost: 1  Cardinality: 1  
            7 TABLE ACCESS BY INDEX ROWID TABLE BBOX.PROGRAMSCORINGEXCLUSION Cost: 1  Bytes: 37  Cardinality: 1         
                6 INDEX RANGE SCAN INDEX BBOX.XXIE1PROGRAMSCORINGEXCLUSION Cost: 1  Cardinality: 1  

как мы можем увидеть, каков фактический план для оператора, когда он фактически выполняется?Мы можем сказать, что читает таблицы выше.Возможно ли, что фактический план отличается от того, который мы видим, и на самом деле он выполняет какое-то картезианское соединение или что-то странное, на решение которого уходит 40 минут?есть ли способ определить это?

1 Ответ

5 голосов
/ 29 ноября 2011

Чтобы найти используемый план, вы можете запросить v $ sql_plan с помощью sql_id.Самое простое, что нужно сделать - это добавить комментарий в запрос, чтобы сделать его уникальным, например,

select /* FROM C++ */ ....

и

select /* FROM SQLPLUS */ ....

Затем выполнить запрос.Запрашивая из v $ sql, вы можете найти SQL_ID запроса, например:

select sql_id, sql_fulltext
from v$sql
where upper(sql_fulltext) like '%FROM C++%';

Затем, используя этот SQL_ID, вы можете запросить v $ sql_plan, чтобы получить план, или, лучше, используйте следующий запрос:

select * from table(dbms_xplan.diplay_cursor('SQL ID OBTAINED ABOVE'));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...