Відкрито про СУБД oracle російською перенесення таблиці в інше табличний простір (racle) розсилка

Випуски розсилки читають вже близько 6000 чоловік, а сайт щодня відвідують до 100 осіб, в основному, з Росії та України. Хоча, по пошуковим запитам і "зарубіжних" відвідувачів буває чимало. Головне - це майже стовідсотково цільова аудиторія: розробники додатків, адміністратори баз даних і взагалі все, так чи інакше цікавляться технологіями Oracle і базами даних.

Чекаю ваших пропозицій.

Як виконується alter table. move tablespace?

Чи не міг би ти пояснити, як реалізований оператор alter table t_name move tablespace. Це можна робити в оперативному режимі (online) і без журналізації (з опцією nologging). Але як дані перенісши з одного табличного простору в інше? Чи доводиться сервера формувати оператори insert і передавати дані через буферний кеш як при звичайній вставці або відбувається щось типу безпосередній вставки?

Я зіткнувся з такою проблемою, для якої хотів би знайти швидкий спосіб вирішення:

Є таблиця розміром 2,5 Гбайта. Я хочу перенести її з табличного простору a в b. Всі файли a і b розбиті на смуги і знаходяться на різних дисках. Ця таблиця - незалежна. Я маю на увазі, що для неї не задані тригери і обмеження цілісності.

Перший спосіб:

Другий спосіб:

Чи буде другий спосіб працювати швидше, ніж перший, за рахунок використання безпосередньої вставки?

Який сопособ буде працювати швидше, і чому? Чи допускає перший спосіб розпаралелювання? Булет є суттєва різниця у використанні сегмента відкоту і простору для сортування?

Відповідь Тома Кайта

Дія move в оперативному режимі може виконуватися ТІЛЬКИ для таблиці, організованої за індексом (index organized table - IOT), але не для звичайної таблиці, організованої у вигляді купи.

Має сенс робити так:

Оператор alter table t move tablespace b nologging; перенесе таблицю (з журнализацией, якщо вона була встановлена), а потім встановить атрибут nologging.

При виконанні move для перенесення таблиці SQL не використовується. Ніякі вставки не виконуються.

Таке перенесення хороший тим, що всі індекси, привілеї і т.п. залишаються. Необхідно тільки перебудувати (але не перестворити) індекси після перенесення.

Другий спосіб може спрацювати швидше, якщо використовувати паралельні вставки (перевірте, що для завдання підказок оптимізатору використовується / * +. А не просто / *.) Але для цього вам доведеться більше попрацювати. Для таблиці розміром 2,5 Гбайт я не впевнений, що воно того варто - може знадобитися більше часу на розробку процедури перенесення, ніж на сам перенесення.

Перенесення табличного простору з опцією nologging

У Oracle Enterprise Edition 8.1.7.2 я роблю наступне:

Я не знаю, працює це з журнализацией або без, але після перенесення таблиця в режим nologging не переводиться. А у версії Oracle 8.1.6 результат інший?

Відповідь Тома Кайта

Добре, параметр logging / nologging має два значення, в залежності від контексту.

У тому контексті, де ви використовували його вище, ви попросили перенесення виконувати без журналізації, якщо об'єкт допускає роботу без журналлізаціі.

Якщо виконати оператор "alter table t nologging", відбувається зміна атрибута logging / nologging.

Як завжди, зрозуміти це допоможе приклад. Ми створимо таблицю, перенесемо її і подивимося, скільки даних повторного виконання буде згенеровано при використанні різних методів переносу:

Отже, є тестова таблиця. Вона спочатку створена в табличному просторі UTILS і:

її режим журналізації - YES (журнализация встановлена). Тепер давайте подивимося, скільки даних повторного виконання вже згенерував сеанс, і збережемо це значення в підставляється змінної V

А тепер виконаємо вашу команду. Цю команду можна російською мовою сформулювати так: "Перенести таблицю T в табличний простір users, і, до речі, якщо можна, БЕЗ журналізації". Зокрема, ця команда НЕ каже: "Перенести таблицю і змінити режим журналізації".

Отже, ми бачимо, що згенеровано близько 4 Мбайт даних повторного виконання - здається, що дія, фактично, журналізіруется. Це можна підтвердити, змінити режим журналізації:

і знову перенісши цю таблицю:

Тепер ми згенерували лише 26 Кбайт даних повторного виконання - цього достатньо для реєстрації змін в словнику даних, але не змін перенесених блоків. Ми перенесли об'єкт без журналізації всіх змін.

Фактично ми з'ясували, що не можна одночасно переносити об'єкт і змінювати його будь-яким іншим способом (ці опції взаємовиключні - ви або переносите об'єкт, або змінюєте його в інший спосіб - одночасно це робити не можна)

Чи можна відновити дію, якщо використовується nologging?

Якщо відбувається збій бази даних і доведеться відновлювати її після використання nologging для перенесення, чи можна буде відновити цю дію. А після відновлення буде тавбліца в вихідному табличному просторі?

Відповідь Тома Кайта

Це залежить від причини збою та інших обставин.

У базі даних, що працює в режимі noarchivelog. оскільки відновлюватися можна тільки на момент останньої повної резервної копії, виконаної в холодному режимі, при збої носія це питання взагалі не актуальне (тому й треба працювати в режимі archivelog!).

Що значить "таблиця, організував у вигляді купи"?

Відповідь Тома Кайта

Таблиці, організовані у вигляді купи

Таблиці, організовані у вигляді купи, використовуються додатками в 99 (якщо не більше) відсотках випадків, хоча з часом це може змінитися за рахунок більш інтенсивного використання таблиць, організованих за індексом, - адже за такими таблицями тепер теж можна створювати додаткові індекси. Таблиця, організована у вигляді купи, створюється за замовчуванням при виконанні оператора CREATE TABLE. Якщо необхідно створити таблицю іншого типу, це треба явно вказати в операторі CREATE.

"Купа" - класична структура даних, яка вивчалася в курсах програмування. Це по суті велика область простору на диску або в пам'яті (в разі таблиці бази даних, звичайно ж, на диску), яка використовується довільним чином. Дані розміщуються там, де для них знайдеться місце, а не в певному порядку. Багато хто вважає, що дані будуть отримані з таблиці в тому ж порядку, в якому туди записувалися, але при організації у вигляді купи це не гарантовано. Фактично гарантовано якраз протилежне: рядки будуть повертатися в абсолютно непередбачуваному порядку. Це дуже легко продемонструвати. Створимо таку таблицю, щоб в моїй базі даних в блоці містилася одна повна рядок (я використовую блоки розміром 8 Кбайт). Зовсім не обов'язково створювати приклад з одним рядком в блоці. Я просто хочу продемонструвати передбачувану послідовність подій. Така поведінка буде спостерігатися для таблиць будь-яких розмірів і в базах даних з будь-яким розміром блоку:
.

Списки вільних місць

Я переніс таблиці в нове локально кероване табличний простір, а потім проаналізував таблиці. Мені цікаво, чому стовпець NUM_FREELIST_BLOCKS = 0 в dba_tables. У всіх таблицях є невикористовувані блоки, а в одному блоці - лише кілька рядків.

Відповідь Тома Кайта

Тому, що блоки, в яких НІКОЛИ не було даних, будуть вище позначки максимального рівня, а не в списках вільних місць.

У списки вільних місць блоки потрапляють після використання - якщо вони ніколи не використовувалися, то в списку вільних місць їх не буде.

Відразу після перевтілення, як у вашому випадку, цілком природно, що в списку вільних місць блоків МАЛО, якщо взагалі вони там є. Це просто означає, що всі існуючі блоки даних "упаковані" - в них більше не можна вставляти рядки. Після зміни / видалення даних деякі блоки опиняться в списку вільних місць.

Розглянемо наступний приклад (табличний простір system управляється за словником, а табличний простір users - локально кероване):

Щільно упаковані таблиця - ніяких блоків в списку вільних місць поки немає.

А тепер - є; ми додали блоки в списки вільних місць, видаливши деякі рядки.

Тепер їх знову немає - всі вільні блоки знаходяться вище позначки максимального рівня (HWM), а не в списках вільних місць.

а ось знову з'явилися - таблиця більше не "упакована", так як при видаленні частина місця звільнилася

Перенесення таблиць в 7.3.4 Parallel Server

Ми використовуємо Oracle 7.3.4 Parallel Server в ОС NCR SVR4 (на неформатованих дисках). Я також використав другий підхід для перенесення таблиць в інші табличні простору, оскільки в версії 7.3.4 оператор alter table move tablespace. Я робив так:

Потім я знову створив індекси за таблицею orgfoo. Мені хотілося б знати:

a) Гарне чи це рішення для версії 7.3.4? Я знайшов твоє рішення на сайті, де рекомендується:

  • Експортувати схему користувача
  • Видалити всі об'єкти користувача
  • Відібрати привілей unlimited tablspace у користувача
  • Змінити стандартне табличний простір для користувача
  • Імпортувати дані користувача

Але я хочу перенести тільки одну велику таблицю, а не всі таблиці. Після видалення всіх об'єктів, як мені імпортувати дані в два різних табличних простору?

b) Після перейменування таблиці, чи треба перебудувати всі уявлення до запуску програми?

c) Для таблиці orgfoo (в табличному просторі EHISTDAT) виділено 250 Мбайт. Цю інформацію я отримав з dba_data_files і dba_free_space перед видаленням таблиці orgfoo.

А при запиті після створення таблиці tempfoo в EKATSDAT і видалення таблиці orgfoo. я отримав наступний результат:

Кількість екстентів і блоків в поданні dba_extents теж відрізняється. У табличному просторі EHISTDAT звільнилося 250 Мбайт, а в табличному просторі було виділено не 250, а всього лише 110 Мбайт. Чи не могли б це пояснити? Чи вважаєте ви подібні дії корисними для економії місця на диску?

Відповідь Тома Кайта

Ваш метод цілком прийнятний. Можна зробити експорт окремої ТАБЛИЦІ, а не всієї схеми - це теж підійде, але і ваш метод відмінно підходить (якщо тільки перебудувати всі обмеження, тригери, привілеї і т.п. - все це утиліта EXP робить автоматично).

Після перейменування таблиці нічого робити не потрібно. Уявлення самі про себе подбають, як і збережені процедури.

Що стосується відмінності "розмірів" - новостворена таблиця заново "упакована". В результаті, вона цілком може виявитися "менше". А от щодо "корисності для економії місця" - я так не думаю. Через пару тижнів / місяців таблиця знову виросте до колишнього розміру. Це як коли сідають на дієту - вага трохи зменшується, але в кінцевому підсумку він знову збільшується до "комфортного". Регулярна реорганізація таблиць:

a) мені не здається потрібної

b) мною не рекомендується (при цьому часто доводиться чути "млинець, частина даних втрачена" через помилки по ходу реогранізації)

c) місце на диску "економить" на пару днів, а згодом розмір знову збільшується до колишнього стабільного рівня.

Збій примірника при перенесенні таблиці з опцією nologging

Що станеться при збої примірника по ходу перенесення таблиці з опцією nologging? Ми дані не втратимо? Це не небезпечно?

Відповідь Тома Кайта

Ні, nologging впливає тільки на відновлення після збою НОСІЯ, але не після збою примірника.

При перенесенні таблиці з опцією nologging таблиця копіюється з постійного сегмента під ТИМЧАСОВИЙ сегмент. У самому кінці цього дії, тимчасовий сегмент перетвориться в постійний - Вото тоді копія і стає реальною таблицею.

Якщо збій примірника відбудеться по ходу перенесення, процес SMON просто очистить тимчасовий сегмент, і все буде виглядати так, як якщо б ми взагалі таблицю не чіпали (постійний сегмент залишається на місці).

Якщо збій примірника відбудеться після перенесення - все в порядку, оскільки дані писалися безпосередньо на диск і відновлювати їх при відновленні примірника не потрібно.

Якщо після перенесення частину даних змінена, зміна зафіксовано і стався збій - тоде все в порядку, оскільки дані повторного виконання для цих змін доступні і їх можна відновити.

Якщо після перенесення і ДО резервного копіювання файлів, які були порушені дією з опцією nologging відбудеться збій ДИСКУ - тоді так, "у нас проблеми". Ось чому у виробничому середовищі є підстави опцію NOLOGGING не використовувати, а якщо вже використовувати, то:

  • спочатку створити резервну копію об'єктів;
  • виконати дію без журналізації;
  • знову створити резервну копію об'єктів.

Отже, проблем при збої примірників взагалі не виникає!

Відповідь Тома Кайта

Виконувати оператори ЯМД можна тільки якщо дія виконується "online" (alter index rebuild online. Наприклад, alter table move online - але тільки для таблиць, організованих за індексом).

У Oracle9i є пакет dbms_redefinition для перевтілення в режимі online більшості об'єктів (що дозволяє виконувати оператори ЯМД по ходу перенесення).

Я бачив твій приклад перенесення таблиці. У ньому замість 4 Мбайт даних повторного виконання (якщо при перенесенні була включена журнализация) генерувалося всього 26 Кбайт.

Я спробував зробити те ж саме, але не побачив різниці. Чи не міг би ти сказати, що я роблю не так. Ось мої результати:

Як бачиш, коли таблиця журналізіровалась, було згенеровано 54320 байта даних повторного виконання, в без журналізації - 53908 байт. Навіть більше на 412 байт.

Відповідь Тома Кайта

Ви працюєте в режимі noarchivelog.

У цьому режимі для цієї дії не потрібно генерувати дані повторного виконання - ось вони і не генеруються, незалежно від установки logging / nologging.

Розпаралелювання?

Отже, якщо необхідно "перенести" таблицю в інше табличний простір (наприклад, з керованого по словнику в локально кероване) швидше буде використовувати INSERT / * + APPEND * /. перевести таблицю в режим nologging. а не використовувати move (з опцією nologging)?

А як щодо розпаралелювання в Oracle 8.1.6 STANDARD? Чи можна використовувати щось на кшталт:

Команда працює, але я не знаю, як перевірити, чи було розпаралелювання при виконанні.

Порадьте, з точки зору тільки продуктивності, що краще - INSERT з APPEND nologging або move nologging.

Відповідь Тома Кайта

Розпаралелювання можливо тільки в EE і PE. Див. В документації

Так що, в SE розпаралелювання недоступно.

Але чому вам здалося, що insert / * + append * / повинно бути краще?

Я б просто переклав таблицю T в режим nologging і переніс її:

Це простіше, ніж insert append. при цьому не втрачаються привілеї та індекси.

(Пороверіть, що дія распараллеливается, можна виконавши запит до v $ px_processes по ходу виконання дії)

Я протестував обидва способи, але не в середовищі SQL * Plus, так що прощу вибачення, що не можу просто вирізати і вставити "всю правду".

Я створив два табличних простору. Я створив таблицю на базі dba_objects і подвоював її поки в ній не виявилося

1,8 мільйона рядків.

350 Мбайт при розмірі блоку 16 Кбайт.

Потім я переклав таблицю в режим nologging (без розпаралелювання).

Тестова машина - двопроцесорний, з Oracle 8.1.6 EE і звичайними дисками (без RAID). При тестуванні кожен тест виконувався мінімум двічі:

Якщо треба, я повторю ці ж тести в середовищі SQL * Plus і скопіюють результати.

Отже, чому insert / * + append * / виконується швидше, ніж move?

Даних повторного виконання генерувалося від 200 до 350 Kбайт.

Відповідь Тома Кайта

Я б сказав, що різниця між 137 і 125 секундами (загального часу виконання) не істотна. 12 секунд ні про що не говорять - особливо на комп'ютері, що виконує ще якісь дії.

Але, як показивапет ваш же тест, alter table move parallel 2 працює в 2 рази швидше (перша спроба розпаралелювання могла працювати повільніше через те, що довелося запускати дочірні процеси PQ - а оскільки запуск 4 процесів зайняв так багато часу, можливо, були конфлікти при доступі до вихідного або цільовим диску).

Я б не робив на цій підставі висновку, що insert append працює швидше. Я б сказав, що це набагато складніше, менш зручно, і взагалі неправильно.

Цікаво, раз таблиця була перенесена, то її індекси стали недійсними і їх треба перебудовувати, - а як індекс перебудовується? По таблиці з новими значеннями rowid (я так думаю) або за існуючим індексом (rowid в якому більше не можна використовувати).

Відповідь Тома Кайта

Необхідно звернутися до таблиці, щоб отримати значення rowid.

Оригінал обговорення цього питання можна знайти тут.

З найкращими побажаннями,