قابلیت Shrink کردن Bigfile tablespace در اوراکل 23ai

از نسخه های قدیمی اوراکل امکان resize کردن دیتافایلها وجود دارد:

SQL*Plus: Release 10.1.0.4.2 - Production on Tue Nov 21 11:15:16 2023
SQL> select bytes/1024/1024 SIZE_MB from v$datafile where file#=29;
   SIZE_MB
----------
      1024
SQL> alter database datafile 29 resize 120m;
Database altered.
SQL> select bytes/1024/1024 SIZE_MB from v$datafile where file#=29;
   SIZE_MB
----------
       120

البته resize کردن دیتافایلها همیشه با موفقیت انجام نمی شود و بعضا با آزاد بودن درصد بالایی از فضای دیتافایل، به دلیل قرار گرفتن بعضی از بلاکهای segment بر سر High Water Mark، امکان کاهش سایز دیتافایل وجود ندارد و در این حالت به خطای زیر برخواهیم خورد:

SQL> alter database datafile 1 resize 10m;
ORA-03297: file contains used data beyond requested RESIZE value

برای جلوگیری از خطای ORA-03297، باید segmentای که بر سر راه High Water Mark قرار دارد را جابجا کنیم! که البته قبلا در مطلبی به طور مفصل این مسئله را بررسی کردیم و از تکرار آن خودداری می کنیم.

مسئله ای که در این متن به آن خواهیم پرداخت، موضوع shrink کردن در سطح tablespaceها است. در نسخه 11g امکان shrink کردن Temporary tablespaceها به وجود آمد:

SQL*Plus: Release 11.2.0.4.0 Production on Tue Nov 21 10:35:57 2023
SQL> select FILE#,BYTES/1024/1024 from v$tempfile where file#=5;
     FILE# BYTES/1024/1024
---------- ---------------
         5            5120
SQL> ALTER TABLESPACE Temp_TBS SHRINK SPACE KEEP 340m;
Tablespace altered.
SQL> select FILE#,BYTES/1024/1024 from v$tempfile where file#=5;
     FILE# BYTES/1024/1024
---------- ---------------
         5             340

و نهایتا در نسخه 23c اوراکل این امکان را برای Bigfile Tablespaceها ارائه کرده است این کار با استفاده از پروسیجر dbms_space.tablespace_shrink امکان پذیر است که در ادامه نحوه استفاده از آن را شرح خواهیم داد.

(بیشتر…)

افزایش حداکثر اندازه Inline LOBها به 8000

در دیتابیس اوراکل LOBها همیشه در LOB segment ذخیره نمی شوند! زمانی که حجم یک LOB از مقدار مشخصی کمتر باشد، این LOB در segment متعلق به خود جدول و در کنار فیلدهای non-LOB ذخیره خواهد شد:

SQL> create table tbl_asnad( id number, doc clob);
Table created
SQL> alter table tbl_asnad rename lob(doc) "SYS_LOB0000136146C00002$$" to lob_asnad_doc;
Table altered
SQL> insert into TBL_ASNAD values(1,'usefzadeh.com');
1 row inserted
SQL> select segment_name,bytes from user_segments where segment_name in ('LOB_ASNAD_DOC','TBL_ASNAD');
SEGMENT_NAME               	  BYTES
----------------------  	----------
TBL_ASNAD                        65536
LOB_ASNAD_DOC                    65536
SQL> begin
  2  for i in 1.. 100000 loop
  3  insert into TBL_ASNAD values(1,'usefzadeh.com');
  4  end loop;
  5  end;
  6  /
PL/SQL procedure successfully completed
SQL> select segment_name,bytes from user_segments where segment_name in ('LOB_ASNAD_DOC','TBL_ASNAD');
SEGMENT_NAME              BYTES
--------------------		 ----------
TBL_ASNAD                	8388608
LOB_ASNAD_DOC             65536

این محدودیت در نسخه 21c برابر 4000 بود و در نسخه 23c به 8000 افزایش یافته است. به ادعای اوراکل، با این قابلیت می توان در زمان عملیاتهایی نظیر Full table scan، Index range scan و DML کارایی بهتری داشت.

جلوگیری از Blocking Session در زمان اجرای دستور Update(قابلیت Lock-free reservation)

شرایطی را در نظر بگیرید که قرار است فیلدی به عنوان شمارنده، دائما توسط تعداد زیادی session بروزرسانی شود(با همزمانی بالا) به این شیوه که با هر بار انجام «اقدامی مشخص»، دستور updateای اجرا شده و یک عدد به این شمارنده اضافه کند.

در این حالت با توجه به زیاد بودن تعداد sessionهای همزمان، احتمال رخ دادن Blocking session هم بسیار افزایش می یابد چرا که در دیتابیس اوراکل اگر دو کاربر قصد ویرایش یک رکورد را داشته باشند و با فاصله زمانی کمی دستور Update را اجرا کنند، کاربری که دیرتر دستور update را صادر کرده Block خواهد شد و تا زمانی که کاربر اول(کاربری که زودتر رکورد را در اختیار گرفته) به تراکنش خاتمه ندهد، کاربر دوم در حالت Block باقی خواهد ماند.

--session 1:
SQL> select sid from v$mystat where rownum=1;
       SID
----------
      2190
SQL> update tbl_counter set counttt=counttt+1;
1 row updated
--session 2:
SQL> select sid from v$mystat where rownum=1;
       SID
----------
       944

SQL> update tbl_counter set counttt=counttt+1;
Executing…

بلاک شدن session دوم را می توانیم از طریق دستور زیر ببینیم:

SQL>  select SID,ID1,ID2,LMODE,block,request from v$lock where type='TX';
       SID        ID1        ID2      LMODE      BLOCK    REQUEST
---------- ---------- ---------- ---------- ---------- ----------
       944     458766       2511          0          0          6
      2190     458766       2511          6          1          0

بنابرین زمانی که کاربران زیادی قصد کار بر روی یک رکورد را دارند، مکانیزم locking امکان ویرایش رکورد را در هر لحظه به یک نفر از آنها خواهد داد و بقیه sessionها Block می شوند. پیدا کردن ترفندی برای جلوگیری از Block شدن sessionها می تواند در بعضی از این شرایط نظیر «شرایط ذکر شده در ابتدای متن» بسیار راهگشا باشد.

(بیشتر…)

امکان استفاده از عبارت if [not] exists در هنگام ایجاد و یا حذف یک object

در زمان ساخت یک object، اگر آن object از قبل موجود باشد، با خطای already exist مواجه خواهیم شد همچنین اگر قصد حذف کردن شی ای که موجود نیست را داشته باشیم، خطای does not exist رخ خواهد داد. برای جلوگیری از این دو خطا می توان از عبارت if [not] exists استفاده کرد.

برای مثال، جدول TB از قبل وجود دارد اگر از این مسئله مطمئن نیستیم، می توانیم دستور ساخت این جدول را با استفاده از عبارت if not exists اجرا کرده تا از خطای احتمالی ORA-00955 جلوگیری کنیم:

SQL> create table tb (c1 number(10));
ORA-00955: name is already used by an existing object
SQL> create table if not exists tb (c1 number(10));
Table created
SQL> create table if not exists tb (c1 number(10));
Table created

این عبارت برای دستورات DDLای دیگر هم کاربرد دارد:

SQL> drop sequence ss;
ORA-02289: sequence does not exist
SQL> drop sequence if exists ss;
Sequence dropped

(بیشتر…)

افزایش حداکثر تعداد ستونهای یک جدول به 4096

تا قبل از اوراکل نسخه 23c، حداکثر تعداد ستونهای یک جدول به عدد 1000 محدود بود:

ORA-01792: maximum number of columns in a table or view is 1000

در نسخه 23c هر جدول می تواند تا 4096 ستون داشته باشد البته برای استفاده از این قابلیت باید پارامتر max_columns را به extended تنظیم کرد:

Connected to Oracle Database 23c Free, Release 23.0.0.0.0 
SQL> create table tb (c1 number(10));
Table created
SQL> alter system set max_columns=extended scope=spfile;
System altered
SQL> declare
  2  comm varchar2(100);
  3  begin
  4    for i in 2..4095 loop
  5     comm:='alter table  tb add c'||''||i||' number';
  6     execute immediate comm;
  7    end loop;
  8  end;
  9  /
  PL/SQL procedure successfully completed
SQL> select count(*) from dba_tab_columns p where p.table_name='TB';
  COUNT(*)
----------
      4095