Oracle начинает делать полное сканирование таблицы, когда столбец изменяется с varchar на nclob - PullRequest
4 голосов
/ 11 октября 2011

У меня есть таблица с примерно 100.000 строк, которая выглядела примерно так:

id      varchar(20),
omg     varchar(10),
ponies  varchar(3000)

При добавлении поддержки международных символов нам пришлось переопределить столбец ponies в nclob, так как 3000 (многобайтовых) символов слишком велики для nvarchar

id      varchar(20),
omg     varchar(10),
ponies  nclob 

Мы читаем из таблицы, используя подготовленный оператор в Java:

select omg, ponies from tbl where id = ?

После того, как столбец «ponies» был изменен на NCLOB и некоторые другие таблицы, в которых были изменены столбцы nchar, Oracle 11g решил выполнить полное сканирование таблицы вместо использования индекса для столбца id, что вызывает наше приложение остановиться.

При добавлении подсказки к запросу используется индекс, и все «хорошо», точнее, чуть медленнее, чем это было, когда столбец был varchar.

Мы определили следующие свойства соединения:

 oracle.jdbc.convertNcharLiterals="true"
 defaultNChar=true

Кстати, статистика базы данных обновляется.

У меня не было времени просмотреть все запросы, поэтому я не знаю, игнорируются ли другие индексы, но нужно ли беспокоиться о том, что настройка defaultNChar как-то сбивает с толку оптимизатор, поскольку идентификатор не является nchar? Было бы довольно неловко либо добавлять подсказки практически ко всем запросам, либо переопределять все ключи.

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

Или это просто невезение? Или что-то другое? Можно ли исправить без подсказок?

Ответы [ 3 ]

3 голосов
/ 29 января 2012

Проблема заключается в том, что jdbc-flag defaultNChar = true.

Оптимизатор Oracles не будет использовать индексы, созданные в столбцах char / varchar2, если параметр отправляется как nchar / nvarchar.Это почти имеет смысл, так как я предполагаю, что вы можете получить фантомные результаты.

В основном мы используем хранимые процедуры с параметрами, определенными как char / varchar2 - форсировать преобразование до выполнения запроса - поэтому мы не сделалиНе замечайте этого эффекта, за исключением нескольких мест, где используется динамический sql.

Решение состоит в том, чтобы преобразовать базу данных в AL32UTF8 и избавиться от столбцов nchar.

2 голосов
/ 11 октября 2011

Когда вы переделывали статистику, вы оценивали или использовали dbms_stats.gather_table_stats с оценочным процентом> 50%?Если вы тогда не использовали dbms_stats со 100% оценка_процента.

Если в вашей таблице только 3 столбца, а именно те, которые вы возвращаете, то лучший индекс - это все 3 столбца, независимо от того, на что вы намекаетедаже если индекс id уникален.В настоящее время ваш план объяснения должен состоять из уникального сканирования индекса с последующим доступом к таблице по rowid.Если вы индексируете все 3 столбца, это становится уникальным сканированием, поскольку вся возвращаемая вами информация будет уже в индексе, и вам не нужно повторно обращаться к таблице, чтобы получить ее.Порядок будет id, omg, ponies, чтобы использовать его в предложении where.Это фактически сделает вашу таблицу index organized table, что будет проще, чем иметь отдельный индекс.Очевидно, что собирать статистику после.

Сказав все, что я на самом деле не уверен, что вы можете индексировать nclob, и независимо от того, что вы делаете, размер столбца будет влиять, поскольку чем дольше он, тем больше дисков читаетвам придется сделать.

0 голосов
/ 11 октября 2011

Извините, но я не понимаю, почему вы изменили свои колонные пони с varchar на clob. Если ваша максимальная длина составляет 3000 символов в этом столбце, почему бы вам не использовать вместо этого столбец NVARCHAR2? Насколько я знаю, nvarchar2 может содержать до 4000 символов.

Но вы правы, максимальный допустимый размер столбца составляет 2000 символов, если набор национальных символов равен AL16UTF16, и 4000, если это UTF8.

...