2010-07-14 2 views
4

MySQL имеет специальный тип MyISAM таблицы, который не поддерживает транзакции. Есть ли у Oracle что-то вроде этого? Я хотел бы создать базу данных для записи (для ведения журнала), которая должна быть очень быстрой (будет хранить много данных) и не требует транзакций.Как использовать Oracle без транзакций?

+3

Нет, и только для записи __should__ базы данных использовать транзакции. Это управление транзакциями, которое позволяет ему roolback при ошибке, чтобы обеспечить согласованность данных. –

+2

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

+0

@MarkBaker, @JeffreyKemp - Я работал с некоторыми фреймворками регистрации (* cough * log4plsql * cough *), чья неэффективная реализация оказала огромное влияние на производительность операций. Поэтому я считаю, что регистрация за короткий промежуток времени большого количества действий - настоящая проблема. Хотя я согласен, что 01 задает неправильный вопрос. – APC

ответ

8

Сделки являются ключевыми для операций базы данных SQL. Они, безусловно, имеют фундаментальное значение в Oracle. Невозможно постоянно писать таблицы Oracle без выдачи коммита, и вот! есть транзакция.

Oracle позволяет нам указывать таблицы как NOLOGGING, которые не генерируют журнал повтора. Это предназначено только для массовой загрузки (с использованием подсказки INSERT /*+ APPEND */), с советами по переключению на LOGGING и как можно скорее отвести назад. Поскольку данные, которые не регистрируются, не подлежат восстановлению. И если вы не хотите его восстанавливать, зачем писать это в первую очередь?

Альтернативный подход заключается в том, чтобы перезаписывать записи в памяти, а затем использовать объемные вставки для их записи. Это довольно быстро.

Вот простая таблица регистрации и доказательство концепции упаковки:

create table log_table 
(ts timestamp(6) 
, short_text varchar(128) 
, long_text varchar2(4000) 
) 
/

create or replace package fast_log is 
    procedure init; 
    procedure flush; 
    procedure write (p_short log_table.short_text%type 
         , p_long log_table.long_text%type); 
end fast_log; 
/

Журнал запись хранится в коллекции PL/SQL, который представляет собой структуру в памяти сессионного объемом. Процедура INIT() инициализирует буфер. Процедура FLUSH() записывает содержимое буфера в LOG_TABLE. Процедура WRITE() вставляет запись в буфер, и если в буфере есть необходимое количество записей, вызывается FLUSH().

create or replace package body fast_log is 

    type log_buffer is table of log_table%rowtype; 
    session_log log_buffer; 

    write_limit constant pls_integer := 1000; 
    write_count pls_integer; 

    procedure init 
    is 
    begin 
     session_log := log_buffer(); 
     session_log.extend(write_limit); 
     write_count := 0; 
    end init; 

    procedure flush 
    is 
    begin 
     dbms_output.put_line('FLUSH::'||to_char(systimestamp,'HH24:MI:SS.FF6')||'::'||to_char(write_count)); 
     forall i in 1..write_count 
      insert into log_table 
       values session_log(i); 
     init; 
    end flush; 

    procedure write (p_short log_table.short_text%type 
         , p_long log_table.long_text%type) 

    is 
     pragma autonomous_transaction; 
    begin 
     write_count := write_count+1; 
     session_log(write_count).ts := systimestamp; 
     session_log(write_count).short_text := p_short; 
     session_log(write_count).long_text := p_long; 

     if write_count = write_limit 
     then 
      flush; 
     end if; 

     commit; 

    end write; 

begin 
    init; 
end fast_log; 
/

Запись в журнал таблицы использует AUTONOMOUS_TRANSACTION прагму, поэтому COMMIT происходит без воздействия на окружающую транзакции вызвавшего флеш.

Вызов DBMS_OUTPUT.PUT_LINE() предназначен для облегчения отслеживания прогресса. Итак, давайте посмотрим, как быстро он идет ....

SQL> begin 
    2  fast_log.flush; 
    3  for r in 1..3456 loop 
    4   fast_log.write('SOME TEXT', 'blah blah blah '||to_char(r)); 
    5  end loop; 
    6  fast_log.flush; 
    7 end; 
    8/
FLUSH::12:32:22.640000::0 
FLUSH::12:32:22.671000::1000 
FLUSH::12:32:22.718000::1000 
FLUSH::12:32:22.749000::1000 
FLUSH::12:32:22.781000::456 

PL/SQL procedure successfully completed. 

SQL> 

Хммм, 3456 записи в 0,12 секунды, что это не так уж и плохо. Основная проблема с этим подходом заключается в необходимости сбросить буфер, чтобы округлить свободные записи; это боль, например. в конце сеанса. Если что-то заставляет сервер терпеть крах, незапланированные записи теряются. Другая проблема с занятием в памяти заключается в том, что она потребляет память (durrrr), поэтому мы не можем сделать кеш слишком большим.

Для сравнения я добавил процедуру к пакету, который вставляет одну запись непосредственно в LOG_TABLE каждый раз, когда он вызывается, снова используя автономные транзакции:

procedure write_each (p_short log_table.short_text%type 
        , p_long log_table.long_text%type) 

is 
    pragma autonomous_transaction; 
begin 
    insert into log_table values (systimestamp, p_short, p_long); 

    commit; 

end write_each; 

Вот его тайминги:

SQL> begin 
    2  fast_log.flush; 
    3  for r in 1..3456 loop 
    4   fast_log.write_each('SOME TEXT', 'blah blah blah '||to_char(r)); 
    5  end loop; 
    6  fast_log.flush; 
    7 end; 
    8/
FLUSH::12:32:44.157000::0 
FLUSH::12:32:44.610000::0 

PL/SQL procedure successfully completed. 

SQL> 

Часы настенные часы, как известно, ненадежны, но пакетный подход в 2-3 раза быстрее, чем один рекорд. Тем не менее, я мог выполнить более трех тысяч дискретных транзакций менее чем за полсекунды, на (далеко от верхнего уровня) ноутбуке. Итак, возникает вопрос: насколько узким местом является регистрация?


Во избежание недоразумений:

@JulesLt отправил свой ответ, когда я работал на моем PoC. Хотя в наших взглядах есть сходство, я считаю, что различия в предлагаемом обходном пути заслуживают публикации этого.


«? Что время для write_each без автономного, но один совершить в конце Моих таймингов предложить это не имеет значения - что наполнитель вставки является большой победой»

Мои тайминги предлагают нечто иное. Замена COMMIT на запись одним COMMIT в конце примерно половину истекшего времени. Еще медленнее, чем объемный подход, но не почти так же.

Главное здесь бенчмаркинг. Мое доказательство концепции работает примерно в шесть раз быстрее, чем тест Жюля (у меня в таблице один индекс). Существуют всевозможные причины, почему это может быть: спецификация машины, версия базы данных (я использую Oracle 11gR1), структуру таблицы и т. Д. Другими словами, YMMV.

Итак, учение: сначала решите, что правильно делать для вашего приложения, а затем сравните это для своей среды. Учитывайте только другой подход, если в вашем тесте указывается серьезная проблема с производительностью. Предупреждение Кнута о premature optimization применяется.

+0

Проголосовали - если бы я больше беспокоился о производительности, чем о целостности, я бы пошел с магазином и флешем. Какое время для write_each без автономной, но одной фиксации в конце? Мои тайминги предполагают, что это неважно, - что нагрузка на вставку является большой победой. – JulesLt

0

Что бы я сделал для аналогичного случая, было бы записать журналы в файл (добавление к файлу, вероятно, самый быстрый способ хранения ваших журналов), а затем включить пакетную вставку этих журналов в БД при помощи регулярные отрезки. Если, конечно, вставка непосредственно в БД достаточно быстра ... но вам нужно будет проверить ...

+0

Файл-приложение будет быстрее для одного потока. Если у вас есть несколько потоков, пытающихся добавить в один и тот же файл, вы получите спор. Либо есть один файл в потоке, либо вы будете быстрее в БД, где он привязан к нескольким потокам, передавая данные в один поток/процесс, который записывает в файл. –

4

Ближайшим может быть создание табличного пространства NOLOGGING и использование опции NOLOGGING для создания таблицы внутри нее - хотя это может применяться только для массовых операций (например, INSERT/* + APPEND */hint).

Это удаляет REDO за счет потери целостности и данных, если БД спускается.

Я не знаю, что на самом деле это будет «быстрее», и вы также должны рассмотреть возможность параллелизма (если у вас много процессов, пытающихся записать в одну и ту же таблицу, вам может быть лучше использовать транзакции, которые пишут ожидающие обновления в повторить журналы, чем пытаться обновить таблицу «real»).

Я еще не исследовал NOLOGGING - я редко попадал в точку, где узким местом приложения была скорость INSERT - когда у меня есть, это была стоимость обновления индексов, а не таблицы, которая была проблемой ,

Я только что проверил быструю проверку и на моей довольно недостаточно развитой БД разработки (с включенным REDO). Используя автономную транзакцию для каждой строки - поэтому каждая строка запускает новую транзакцию и заканчивается фиксацией, я могу записать/зафиксировать более 1000 строк в таблицу индексированных журналов за 1 секунду против примерно 0,755 секунд, делая 1000 вставок без фиксации.

Выполнение вставки из 1000 строк одним ударом с использованием массовой операции - это небольшая часть секунды, поэтому, если вы можете увеличить объем журналов, сделайте это.

Некоторые другие соображения: Может ли внешняя таблица выполнить задание - то есть записать в файл журнала, который затем монтируется в качестве внешней таблицы в Oracle, когда/если вам нужно его прочитать?

0

Это похоже на решение проблемы при поиске.

Вы сравнили производительность? Oracle достаточно быстро для вас, как есть? Управление транзакциями встроено в то, как работает Oracle и пытается обойти его, похоже, что вы создаете работу для себя.

Вы, кажется, идентифицировали управление транзакциями как проблему, не зная, есть ли проблемы. Что произойдет позже, когда у вас будет несколько авторов на столе? Или читатели блокируют писателей?

2

Мой опыт в том, что ведение журнала лучше всего делать с плоским файлом. Мое мнение состоит в том, что журналы обычно не особенно важны - ДОЛЖНО что-то пошло не так, и в это время они становятся критическими. Из-за этого я не хочу осуществлять транзакционное управление моим протоколированием. Если мне нужно отменить транзакцию, потому что есть проблема, я действительно не хочу откатывать данные регистрации, потому что это то, что я собираюсь использовать, чтобы помочь определить, в чем проблема. Кроме того, как вы регистрируетесь, что есть проблема с подключением к базе данных, если журнал хранится в базе данных, с которой невозможно подключиться?

Делитесь и наслаждайтесь.

+0

Если я не могу подключиться к базе данных, я бы ожидал, что DBA будет искать в файле alert.log или DB -генерированный файл .TRC для подсказок, а не в отладочном выходе разработчика. – APC

0

ПРАГМА AUTONOMOUS_TRANSACTION

Это позволит вам войти и совершить свой журнал, не влияя на окружающую сделки (сделок). Регистрация является одним из немногих приемлемых вариантов использования автономных транзакций. Он делает то, что он говорит, позволяет вам написать функцию/процедуру pl/sql, которая может выполнять свою работу, не влияя на транзакцию, в которой она может или не может участвовать. Она «автономна».

au · ton · o · mous 1. (страны или региона) Имея самоуправления. 2. Действуя независимо или имея на это право: «автономный комитет школьного совета».

Oracle docs:

AUTONOMOUS_TRANSACTION Прагма изменяет способ подпрограммы работает в рамках транзакции. Подпрограмма , отмеченная этой прагмой, может выполнять операции SQL и совершать или откатывать эти операции, не совершая или откатывая данные в основной транзакции .

CREATE OR REPLACE FUNCTION FNC_LOG(p_log_text varchar2(4000)) 
RETURN NUMBER 
IS 
PRAGMA AUTONOMOUS_TRANSACTION; 
BEGIN 
    -- Your brief code goes here (don't abuse the evil feature that is autonomous transactions). 
END; 
1

«который должен быть очень быстрым»

Существует компромисс (иногда) между быстрой и возмещена.

В Oracle восстанавливаемость достигается посредством файла журнала повтора. Evey время, которое вы совершили, в журнале «log writer» делает синхронный вызов для записи выдающихся изменений в файл. Синхронно, я имею в виду, что он ожидает, что файловая система подтвердит, что запись была успешной, прежде чем сказать, что фиксация прошла успешно.

Если вы делаете большое количество протоколирования (особенно из-за множества сеансов одновременно), каждая строка в файле журнала выполняется независимо (ag автономная транзакция), то это может быть узким местом.

Если вам не нужен этот уровень восстановления (т. Е. Вы можете позволить себе потерять последние несколько строк ваших данных журнала из ваших журналов в случае серьезного сбоя), посмотрите на вариант фиксации NOWAIT.

Если вы не можете позволить себе потерять что-либо, тогда ваш лучший выбор - ДЕЙСТВИТЕЛЬНО быстрое хранение (это может быть кеш с резервной батареей).

Смежные вопросы