Страницы

Поиск по вопросам

воскресенье, 1 декабря 2019 г.

Большое время выполнения DML запросов

#sql #oracle #производительность


Суть проблемы такова что любые операции с бд выполняются очень долго, к примеру:
.      insert into tab1 (time) values sysdate
Выполняется 40-60 мс. А при записи в бд >1000 значений, получаем очень длительную
запись. Бд oracle 11gR2 ОС Oracle Linux на CentOs аналогичная проблема. Помогите пожалуйста
разобраться.

Оказывается что выгрузка с БД и т.д выполняются почти моментально, проблема только
с INSERT (записью в БД) 

Всё, что использует родной OCI драйвер (sqlplus, dbForge) отрабатывает нормально,
а всё остальное, SQL Net, Thin JDBC (SqlDev, TOAD) тормозит, причём только на DML,
и со стороны ДБ время выполненения выглядит нормально.

internal class Program
    {
        private static void Main()
        {
            var stopwatch = Stopwatch.StartNew();

          //  DateTime dt = new DateTime();
            try
            {
                const string oradb = "Data Source = 192.168.137.70/xe; " +
                                     "User id = useridb; Password = user1234";
#pragma warning disable 618
               var con = new OracleConnection(oradb);
#pragma warning restore 618
                con.Open();


#pragma warning disable 618
                var cmd = new OracleCommand {Connection = con};
#pragma warning restore 618



                for (var i = 0; i < 1000; i++)
                {
                    cmd.CommandText = "Insert into test (datetime) values (sysdate)";
                    //cmd.CommandText = "Select max(datetime) from test";
                    var dr = cmd.ExecuteReader();
                    dr.Read();

                   // dt = Convert.ToDateTime(dr.GetValue(0));
                    dr.Close();
                   // Thread.Sleep(50);
                }



                stopwatch.Stop();
                var averageTime = new TimeSpan(stopwatch.ElapsedMilliseconds / 1000);
                Console.WriteLine("Запись успешна {0},  {1}", averageTime, dt);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error{0}", e.Message);
            }
            Console.ReadKey();
        }
    }

    


Ответы

Ответ 1



На то существует ораклевская инструкция EXPLAIN PLAN, типа: EXPLAIN PLAN FOR INSERT INTO TABLE values(10) выдаст вам что происходит, когда вы делаете вставку записи. Как читать вывод и что делать подробнейшим образом расписано в документации грубо говоря, вы увидите где "бутылочное горлышко" - то ли это формируется VIEW или отрабатывает триггер или условие при вставке или что-то еще.

Ответ 2



Надо включить SQL трассировку. В противоположенность EXPLAIN PLAN, будет показано "то, что уже было", а не "то, что ещё будет". Если и не приведёт к решению проблемы сразу, то даст направление, куда дальше искать. Для начала надо проверить, включена ли TIMED_STATISTICS (по умолчанию включена) и куда пишутся файлы трассировки (обычно $ORA_BASE/diag/rdbms/orasid/orasid/trace): select name, value from v$parameter where name in ('timed_statistics','user_dump_dest'); Выбираем кандидатов, например сессии на удалённом SQL Developer и SQL*Plus локально на сервере БД: select s.username, s.status, s.sid, s.serial#, sql_trace, s.program, p.spid from v$session s join v$process p on s.paddr = p.addr where s.username = 'SH1'; USERNAME STATUS SID SERIAL# SQL_TRAC PROGRAM SPID ------------- -------- ---------- ---------- -------- ------------------------------ ------ SH1 ACTIVE 139 41 DISABLED SQL Developer 26596 SH1 INACTIVE 15 92 DISABLED sqlplus@mpsrv (TNS V1-V3) 25930 Включаем трассировку под пользователем с DBA привилегиями: exec sys.dbms_monitor.session_trace_enable(session_id=>139, serial_num=>41, waits=>true, binds=>false); exec sys.dbms_monitor.session_trace_enable(session_id=>15, serial_num=>92, waits=>true, binds=>false); В выбраных клиентах производим запрос(ы): insert into tab1 (time) values (sysdate); commit; И выключаем трассировку: exec sys.dbms_monitor.session_trace_disable(session_id=>139, serial_num=>41); exec sys.dbms_monitor.session_trace_disable(session_id=>15, serial_num=>92); Находим файлы трассировки в папке user_dump_dest (см. выше) и приводим к читабелному виду с tkprof: $ ls -1t *26596.trc *25930.trc myoradb_ora_25930.trc myoradb_ora_25507.trc tkprof myoradb_ora_25930.trc sqlp_25930.prf explain=sh1/sh1 tkprof myoradb_ora_26596.trc sqld_26596.prf explain=sh1/sh1 Выход tkprof будет выглядеть где-то так: ******************************************************************************** count = number of times OCI procedure was executed cpu = cpu time in seconds executing elapsed = elapsed time in seconds executing disk = number of physical reads of buffers from disk query = number of buffers gotten for consistent read current = number of buffers gotten in current mode (usually for update) rows = number of rows processed by the fetch or execute call ******************************************************************************** SQL ID: f281fbsngrwq0 Plan Hash: 0 insert into tab1 (time) values (sysdate) call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 1 5 1 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 2 0.00 0.00 0 1 5 1 Misses in library cache during parse: 1 Optimizer mode: ALL_ROWS Parsing user id: 151 (SH1) Rows Row Source Operation ------- --------------------------------------------------- 0 LOAD TABLE CONVENTIONAL (cr=1 pr=0 pw=0 time=0 us) Rows Execution Plan ------- --------------------------------------------------- 0 INSERT STATEMENT MODE: ALL_ROWS 0 LOAD TABLE CONVENTIONAL OF 'TAB1' Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ SQL*Net message to client 1 0.00 0.00 SQL*Net message from client 1 0.00 0.00 ******************************************************************************** Для сравнения, в SQL Developer заметно значительное ожидание ответа от клиента, т.к. не высокоскоростное соединение с сервером. И кроме того, SQL ID отличается, т.е. оракле не распознал запрос как идентичный: ******************************************************************************** SQL ID: gck3089qg8n7x Plan Hash: 0 insert into tab1 (time) values (sysdate) ... Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ Disk file operations I/O 1 0.00 0.00 log file sync 1 0.01 0.01 SQL*Net message to client 1 0.00 0.00 SQL*Net message from client 1 4.07 4.07 Подробнее о других возможностях и чтении форматированного вывода tkprof в документаци. Замечу: имеет смысл трассировка в конфигурации выделенного сервера, в случае распределённых серверов очень трудоёмкая задача собирать трассировку, т.к. даже один запрос может быть распарсен в одном сервере, а выполнен в другом.

Комментариев нет:

Отправить комментарий