Вы находитесь на странице: 1из 9

Использование отладки SQL

Рекомендовано для:
• Oracle Database 8i
• Oracle Database 9i R1
• Oracle Database 9i R2
• Oracle Database 10g R1
• Oracle Database 10g R2
• Oracle Database 11g R1

В статье пойдет речь о различных способах включения отладки SQL.


Включение отладки для своей сессии, выполняется командой:
ALTER SESSION SET sql_trace=TRUE;
или
ALTER SESSION SET EVENTS '10046 trace name context forever, level <уровень_отладки>';
где, уровень отладки:
0 - Выключить отладку (значение по умолчанию)
1 - Включить отладку.
4 - Добавить в отладку информацию о значениях связанных переменных
8 - Добавить в отладку информацию об ожиданиях
12 - Комбинация уровней 4 и 8
В итоге команда может выглядеть так:
ALTER SESSION SET EVENTS '10046 trace name context forever, level 12';
Чтобы включить отладку для выбранной сессии, выполняем SQL команду:
EXEC sys.dbms_system.set_sql_trace_in_session([SID],[serial#], TRUE);
или
EXEC sys.dbms_system.set_ev([SID], [serial#], 10046, уровень_отладки, '');
Значения SID и serial# сессии можно найти в v$session:
SELECT SID, SERIAL# FROM V$SESSION;
SID SERIAL#
---------- ----------
133 46
136 4
137 6
138 8
140 22905
Если требуется включить отладку для всех сессий экзмемпляра, то в файле конфигурации init.ora
необходимо выставить параметр sql_trace=true и перегрузить экземпляр. Выставлять отладку для
всех сессий рекомендуется только в экстренных случаях, поскольку это создаст значительную
нагрузку на сервер.
Кроме того, вы можете сделать трассировку любого серверного процесса, используя oradebug.
Зная SID процесса можно получить его PID (Oracle Process Identifier) или его SPID (Operating
System process identifier):
SELECT P.SPID, P.PID
2 FROM V$PROCESS P, V$SESSION S
3 WHERE P.ADDR = S.PADDR
4 AND S.SID = SID;
Затем выполняем любую из команд, для указания процесса:
SVRMGR> ORADEBUG SETOSPID [SPID]
либо
SVRMGR> ORADEBUG SETORAPID [PID]
И включаем отладку командой:
SVRMGR> ORADEBUG EVENT 10046 trace name context forever, level уровень_отладки
Еще один вариант включения отладки, описан у Тома Кайта. Для включения отладки на уровне
сессии используется logon-тригер. Этот вариант исключительно полезен, когда необходимо
получить отладочную информацию о сессии, которая работает очень непродолжительное время
(секунды).
CREATE OR REPLACE TRIGGER trace_login_trigger
AFTER logon ON DATABASE
BEGIN
IF (USER = '') THEN
EXECUTE IMMEDIATE 'ALTER SESSION SET EVENTS ''10046 trace name
context forever, level ''';
END IF;
END;
По завершении сбора данных, триггер переводится в состояние 'DISABLE'. Для отключение
триггера выполните команду SQL:
ALTER TRIGGER trace_login_trigger DISABLE;
Когда триггер снова потребуется собрать отладочную информацию, включаете триггер командой:
ALTER TRIGGER trace_login_trigger ENABLE;

Фрагментация таблиц в Oracle


Рекомендовано для:

• Oracle Database 9i R1
• Oracle Database 9i R2
• Oracle Database 10g R1
• Oracle Database 10g R2
• Oracle Database 11g R1

Когда строки не сохраняются рядом, или если строки разбиты больше чем в один блок,
снижается производительность, потому что эти строки требуют дополнительного доступа к
блокам.
Следует понимать, что фрагментация таблиц отлична от файловой фрагментации. Когда
выполняется серия операций DML над таблицей, таблица фрагментируется, потому что DML не
освобождает свободное пространство до HWM.
HWM - это индикатор использования блоков (USED BLOCKS) в базе данных. Блоки идущие до
линии HWM - используемые блоки и содержат данные. Эти данные могут быть удалены. Oracle
знает какие блоки до HWM не содержат данных, он читает блоки выше HWM, когда выполняет
полное сканирование таблицы.
DDL предложение всегда сбрасывает HWM.

Как найти фрагментацию таблицы?


SQL> SELECT COUNT(*) FROM BIG1;
1000000 rows selected.

SQL> DELETE FROM BIG1 WHERE ROWNUM <= 300000;


300000 rows deleted.

SQL> COMMIT;
Commit complete.

SQL> UPDATE BIG1 SET OBJECT_ID = 0 WHERE ROWNUM <=350000;


342226 rows updated.

SQL> COMMIT;
Commit complete.
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT','BIG1');
PL/SQL procedure successfully completed.
Размер таблицы (с фрагментацией)
SQL> SELECT TABLE_NAME, ROUND((BLOCKS*8),2)//'KB' "SIZE"
2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 72952KB
Реальные данные:
SQL> SELECT TABLE_NAME, ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)//'KB' "SIZE"
2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 30604.2KB
Итог = 72952 - 30604 = 42348 Kb используется без толку.
Разница между двумя значениями почти 60% и Pctfree 10% (по-умолчанию), в итоге, 50%
пространства не используется и простаивает, потому что не содержит данных.

Как сбросить HWM/убрать фрагментацию?


Для этого потребуется реорганизовать фрагментированную таблицу.
Есть четыре опции для реорганизации фрагментированных таблиц:
1. alter table ... move + rebuild indexes
2. export / truncate / import
3. create table as select (CTAS)
4. dbms_redefinition

Опция 1 "alter table ... move + rebuild indexes"


SQL> ALTER TABLE BIG1 MOVE;
TABLE altered.

SQL> SELECT STATUS, INDEX_NAME FROM USER_INDEXES


2 WHERE TABLE_NAME = 'BIG1';
STATUS INDEX_NAME
-------- ------------------------------
UNUSABLE BIGIDX

SQL> ALTER INDEX BIGIDX REBUILD;


Index altered.

SQL> SELECT STATUS, INDEX_NAME FROM USER_INDEXES


2 WHERE TABLE_NAME = 'BIG1';
STATUS INDEX_NAME
-------- ------------------------------
VALID BIGIDX

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT','BIG1');


PL/SQL procedure successfully completed.

SQL> SELECT TABLE_NAME, ROUND((BLOCKS*8),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 38224KB

SQL> SELECT TABLE_NAME, ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 30727.37KB

Опция: 2 "Create table as select"


SQL> CREATE TABLE BIG2 AS SELECT * FROM BIG1;
TABLE created.

SQL> DROP TABLE BIG1 PURGE;


TABLE dropped.

SQL> RENAME BIG2 TO BIG1;


TABLE renamed.

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT','BIG1');


PL/SQL procedure successfully completed.

SQL> SELECT TABLE_NAME,ROUND((BLOCKS*8),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 85536KB

SQL> SELECT TABLE_NAME,ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 68986.97KB

SQL> SELECT STATUS FROM USER_INDEXES


2 WHERE TABLE_NAME = 'BIG1';
no rows selected

SQL> --Важно, потребуется заново создать все индексы.

Опция: 3 "export/truncate/import"
SQL> SELECT TABLE_NAME, ROUND((BLOCKS*8),2)//'KB' "SIZE"
2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 85536KB

SQL> SELECT TABLE_NAME, ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 42535.54KB

SQL> SELECT STATUS FROM USER_INDEXES WHERE TABLE_NAME = 'BIG1';


STATUS
--------
VALID
SQL> EXIT
Disconnected from Oracle Database 10g Enterprise Edition Release 10.1.0.5.0 - Production
With the Partitioning, OLAP and Data Mining options
C:\>exp scott/tiger@Orcl file=c:\big1.dmp tables=big1
Export: Release 10.1.0.5.0 - Production on Sat Jul 28 16:30:44 2007
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.1.0.5.0 - Production
With the Partitioning, OLAP and Data Mining options
Export done in WE8MSWIN1252 character set and AL16UTF16 NCHAR character set
About to export specified tables via Conventional Path ...
. . exporting table BIG1 468904 rows exported
Export terminated successfully without warnings.
C:\>sqlplus scott/tiger@orcl
SQL*Plus: Release 10.1.0.5.0 - Production on Sat Jul 28 16:31:12 2007
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.1.0.5.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL> TRUNCATE TABLE BIG1;
TABLE truncated.

SQL> EXIT
Disconnected from Oracle Database 10g Enterprise Edition Release 10.1.0.5.0 - Production
With the Partitioning, OLAP and Data Mining options
C:\>imp scott/tiger@Orcl file=c:\big1.dmp ignore=y
Import: Release 10.1.0.5.0 - Production on Sat Jul 28 16:31:54 2007
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.1.0.5.0 - Production
With the Partitioning, OLAP and Data Mining options
Export file created by EXPORT:V10.01.00 via conventional path
import done in WE8MSWIN1252 character set and AL16UTF16 NCHAR character set
. importing SCOTT's objects into SCOTT
. . importing table "BIG1" 468904 rows imported
Import terminated successfully without warnings.
C:\>sqlplus scott/tiger@orcl
SQL*Plus: Release 10.1.0.5.0 - Production on Sat Jul 28 16:32:21 2007
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.1.0.5.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL> SELECT TABLE_NAME, ROUND((BLOCKS*8),2)//'KB' "SIZE"
2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 85536KB

SQL> SELECT TABLE_NAME, ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 42535.54KB

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT','BIG1');


PL/SQL procedure successfully completed.

SQL> SELECT TABLE_NAME, ROUND((BLOCKS*8),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 51840KB

SQL> SELECT TABLE_NAME, ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'BIG1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
BIG1 42542.27KB

SQL> SELECT STATUS FROM USER_INDEXES WHERE TABLE_NAME = 'BIG1';


STATUS
--------
VALID

SQL> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('SCOTT','BIG1',-


> DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL procedure successfully completed.

Опция: 4 "dbms_redefinition"
SQL> CREATE TABLE TABLE1 (
2 NO NUMBER,
3 NAME VARCHAR2(20) DEFAULT 'NONE',
4 DDATE DATE DEFAULT SYSDATE);
TABLE created.

SQL> ALTER TABLE TABLE1 ADD CONSTRAINT PK_NO PRIMARY KEY(NO);


TABLE altered.

SQL> BEGIN
2 FOR X IN 1..100000 LOOP
3 INSERT INTO TABLE1 ( NO , NAME, DDATE)
4 VALUES ( X , DEFAULT, DEFAULT);
5 END LOOP;
6 END;
PL/SQL procedure successfully completed.

SQL> CREATE OR REPLACE TRIGGER TRI_TABLE1


2 AFTER INSERT ON TABLE1
3 BEGIN
4 NULL;
5 END;
Trigger created.

SQL> SELECT COUNT(*) FROM TABLE1;


COUNT(*)
----------
100000

SQL> DELETE TABLE1 WHERE ROWNUM <= 50000;


50000 rows deleted.

SQL> COMMIT;
Commit complete.

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT','TABLE1');


PL/SQL procedure successfully completed.

SQL> SELECT TABLE_NAME, ROUND((BLOCKS*8),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'TABLE1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
TABLE1 2960KB

SQL> SELECT TABLE_NAME, ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'TABLE1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
TABLE1 822.69KB

SQL> --Требуется роль "DBA" или "SELECT" на dbms_redefinition pkg


SQL> --Проверьте что таблица кандидат на переопределение.
SQL>
SQL> EXEC SYS.DBMS_REDEFINITION.CAN_REDEF_TABLE
2 ('SCOTT',-> 'TABLE1',->
3 SYS.DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL procedure successfully completed.

SQL> -- После проверки таблицы на возможность переопределения, вручную


SQL> -- создается пустая временная таблица (в той же схеме и точно такая же
SQL> -- как переопределяемая)
SQL>
SQL> CREATE TABLE TABLE2 AS SELECT * FROM TABLE1 WHERE 1 = 2;
TABLE created.

SQL> EXEC SYS.DBMS_REDEFINITION.START_REDEF_TABLE


2 ( 'SCOTT',-> 'TABLE1',-> 'TABLE2');
PL/SQL procedure successfully completed.

SQL> --Эта процедура синхронизирует две таблицы, исходную и временную.


SQL>
SQL> EXEC SYS.DBMS_REDEFINITION.SYNC_INTERIM_TABLE
2 ('SCOTT',-> 'TABLE1',-> 'TABLE2');
PL/SQL procedure successfully completed.

SQL> --Создаем PRIMARY KEY на временную таблицу(TABLE2)


SQL> ALTER TABLE TABLE2
2 ADD CONSTRAINT PK_NO1 PRIMARY KEY (NO);
TABLE altered.

SQL> CREATE TRIGGER TRI_TABLE2


2 AFTER INSERT ON TABLE2
3 BEGIN
4 NULL;
5 END;
Trigger created.

SQL> -- Отключаем внешний ключ на оригинальной таблице,


SQL> -- если существует, прежде чем завершить процесс.
SQL>
SQL> EXEC SYS.DBMS_REDEFINITION.FINISH_REDEF_TABLE
2 ( 'SCOTT',-> 'TABLE1',-> 'TABLE2');
PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT','TABLE1');


PL/SQL procedure successfully completed.

SQL> SELECT TABLE_NAME, ROUND((BLOCKS*8),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'TABLE1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
TABLE1 1376KB

SQL> SELECT TABLE_NAME, ROUND((NUM_ROWS*AVG_ROW_LEN/1024),2)//'KB' "SIZE"


2 FROM USER_TABLES
3 WHERE TABLE_NAME = 'TABLE1';
TABLE_NAME SIZE
------------------------------ ------------------------------------------
TABLE1 841.4KB

SQL> SELECT STATUS,CONSTRAINT_NAME


2 FROM USER_CONSTRAINTS
3 WHERE TABLE_NAME = 'TABLE1';
STATUS CONSTRAINT_NAME
-------- ------------------------------
ENABLED PK_NO1

SQL> SELECT STATUS ,TRIGGER_NAME


2 FROM USER_TRIGGERS
3 WHERE TABLE_NAME = 'TABLE1';
STATUS TRIGGER_NAME
-------- ------------------------------
ENABLED TRI_TABLE2

SQL> DROP TABLE TABLE2 PURGE;


TABLE dropped.
Какой из способов подходит вам, смотрите по ситуации.

Oracle и регулярные выражения


Unix пришел в Oracle в форме регулярных выражений, чтобы увеличить мощь поиска.
Я подумал, что неплохо бы посвятить статью регулярным выражениям, тому как мы, включая
меня, знакомимся или освежаем в памяти мощь, которую могут дать эти выражения.
Я познакомился с регулярными выражениями давным-давно, программируя на Perl или
скриптовой оболочке unix с помощью команд awk и sed. Также, если Вы используете vi редактор,
то можете быть знакомыми с регулярными выражениями и сравнением с образцом. Регулярные
выражения в действительности представляют собой маленький язык программирования, который
предназначен для поиска символьных образцов в текстовой строке. Если честно, когда я начал
использовать сравнение с образцом в мои дни Perl, оно показалось мне весьма путаным. Главным
образом, потому что было столь много изменений и вариантов, что я не знал, как начать. Хотя
спустя некоторое время, я приобрел некоторые навыки. И Вы сможете также. Наберитесь
терпения прочесть эту статью и понять, насколько мощным может быть это сравнение с
образцом.
Как уже говорилось, регулярные выражения предназначены для нахождения соответствия в
символьных строках. Другое и возможно немного более ясное определение утверждает, что
регулярные выражения являются шаблонами, с которыми сравниваются строки символов на
предмет совпадения или соответствия строки символов шаблону. Самый близкий пример или
сравнение, которое я могу дать, - это пример, использующий сравнение LIKE, которое предлагает
некоторые формы соответствия шаблону или образцу. Например, если мы хотим найти строку
символов, содержащую 'Deborah', то могли бы написать следующий SQL-запрос.
SELECT text FROM my_text WHERE text LIKE '%Deborah%';
Этот запрос действительно возвратит всякую строку, которая содержит 'Deborah' в любом месте
текста в пределах строки символов. Чтобы сделать быстро аналогичное сравнение с помощью
регулярного выражения, можно выполнить следующий SQL-запрос, который содержит новую
функцию REGEXP_LIKE.
SELECT text FROM my_text WHERE REGEXP_LIKE (text, '\Deborah\');
Итак, зачем мы хотим использовать регулярные выражения вместо того, чтобы просто
использовать сравнение LIKE, с которым мы очень хорошо знакомы? Главным образом, потому,
что как только Вы начинаете задавать высокоуровневые вопросы о "сходстве" строки образцу,
то, наиболее вероятно, закончите условием WHERE c многократными сравнениями 'OR' и 'LIKE',
чтобы вытащить то, что Вы действительно ищете. С помощью регулярных выражений Вы можете
в большинстве случаев написать только один образец сравнения. Возьмем предыдущий пример.
Предположим теперь, что нам требуется найти в романе главный персонаж Deborah, которую
также называют 'Debbie'. В этом случае мы можем изменить наше условие для поиска текста на
LIKE '%Deb%', и тем самым решить проблему. Но что случится, в этом конкретном романе
обсуждаются также финансовое состояние нашей девушки из высшего общества. Мы можем
прекратить поиск, найдя предложения, которые содержат слова типа 'Debt', или 'Debutante'. Мы
теперь имеем очень сложную проблему. Чтобы гарантировать, что мы найдем текст, имеющий
непосредственное отношение к Деборе, мы должны использовать регулярное выражение. Вот
SQL-запрос, который Вы должны выполнить. Теперь он находит все предложения, где в романе
говорится о Деборе.
SELECT text FROM my_text WHERE REGEXP_LIKE (text, '\Deb(bie/orah)\');
Видно, что в пределах образца соответствия мы программируем варианты текста, содержащего
'Debbie' или альтернативу 'Deborah', с помощью опции (bie/orah) в выражении. Это -
каноническая форма построения шаблона, по которому выполняется сравнение строки.
Другой сложный пример, с которым вы можете справиться только используя выражения, находит
адреса электронной почты. Это можно быстро сделать с помощью следующего выражения. При
этом Вы строите части адреса электронной почты перед знаком '@' и после него. Посмотрите
внимательно на этот образец, поскольку он требует трех разных частей адреса электронного
адреса и учитывает присутствие '.', а так же как нижнего подчеркивания '_' в имени. Все эти
символы вполне допустимы.
SELECT text FROM my_text
WHERE REGEXP_LIKE (text, '[A-Z0-9._%-]+@[A-Z0-9._%-]+\.[A-Z]{2,4}');

Теперь, если Вы хотите искать только '.com' адреса электронной почты, то можно изменить SQL-
код на следующий.
SELECT text FROM my_text WHERE REGEXP_LIKE (text, '[A-Z0-9._%-]+@[A-Z0-9._%-]+\.com');
Другая часто вызывающая затруднения проблема - это выяснение того, имеется ли число в
строке текста или проверка того, представляет ли собой число строка символов. Для нахождения
строки, содержащей число, которое соответствует образцу с десятичной точкой, Вы могли бы
использовать этот метод. Имея в виду, что числа, которые имеют десятичную точку, должны
иметь действительное число после десятичной точки, я написал '+', чтобы указать одно или
более чисел.
SELECT text FROM my_text WHERE REGEXP_LIKE (text, '[0-9]?\.[0-9]+');
Регулярные выражения являются мощным орудием, когда ищутся образцы текстов или
проверяется соответствие определенному образцу, подобное телефонному номеру, адресу
электронной почты, IP-адресу или почти любому образцу, который нуждается в проверке.
Обратным вариантом является проверка недопустимых форматов и образцов символов. В нашем
предыдущем примере мы могли бы легко разыскать текст, где 'Debbie' написано с ошибкой,
например, как 'Debbbie' или 'Debie'.
Другая часто вызывающая затруднения проблема - это выяснение того, имеется ли число в
строке текста или проверка того, представляет ли собой число строка символов. Для нахождения
строки, содержащей число, которое соответствует образцу с десятичной точкой, Вы могли бы
использовать этот метод. Имея в виду, что числа, которые имеют десятичную точку, должны
иметь действительное число после десятичной точки, я написал '+', чтобы указать одно или
более чисел.
SELECT text FROM my_text WHERE REGEXP_LIKE (text, '(Debbbie)');

Чтобы получить имена, набранные тяжелыми пальцами, где 'b', возможно, был набит более 3-х
раз; мы можем использовать следующий запрос
SELECT text FROM my_text WHERE REGEXP_LIKE (text, '(Deb)(b){2,}');
Регулярные выражения поначалу могут показаться очень замысловатыми. Мне даже требуются
некоторые усилия, чтобы вспомнить эти образцы, если я не использовал их какое-то время. Но
после некоторых затрат времени на изучение их построения Вы будете вознаграждены,
столкнувшись со сложными критериями поиска.
Итак, где же узнать, как строить регулярные выражения. Это действительно не столь трудно, как
Вы могли бы подумать. Регулярные выражения всегда сопутствовали миру Unix, и поэтому есть
много информации по ним в сети. Руководства Oracle включают несколько страниц, около 5,
которые посвящены регулярным выражениям; поэтому лучше начать отсюда, а в особо тяжелых
случаям обращаться к сети. Вы можете смело довериться Yahoo, Google или любой другой вашей
любимой поисковой машине в поиске руководств и вебсайтов, посвященным исключительно
регулярным выражениям.