У мене в тестовій базі даних є таблиця з 250K рядками. (У виробництві є кілька сотень мільйонів, ми можемо спостерігати ту саму проблему.) У таблиці є рядковий ідентифікатор nvarchar2 (50), не нульовий, з унікальним індексом на ньому (це не ПК).
Ідентифікатори складаються з першої частини, яка містить 8 різних значень у моїй тестовій базі даних (і близько тисячі у виробництві), потім знак @ і, нарешті, число, довжиною від 1 до 6 цифр. Наприклад, може бути 50 тисяч рядків, які починаються з "ABCD_BGX1741F_2006_13_20110808.xml @", а за ним слідує 50 тисяч різних цифр.
Коли я запитую один рядок на основі його ідентифікатора, кардинальність оцінюється як 1, вартість дуже низька, він працює чудово. Коли я запитую більше ніж один рядок з декількома ідентифікаторами у виразі IN чи ІЛИ, то оцінки індексу є абсолютно неправильними, тому використовується повне сканування таблиці. Якщо я змушую індекс натяком, це дуже швидко, сканування повної таблиці фактично виконується на порядок повільніше (і набагато повільніше у виробництві). Тож це проблема оптимізатора.
Як тест, я дублював таблицю (в тій же схемі + простір таблиць) з точно таким же DDL і точно таким же вмістом. Я відтворив унікальний індекс на першій таблиці для гарної міри та створив такий самий індекс на таблиці клонування. Я зробив а DBMS_STATS.GATHER_SCHEMA_STATS('schemaname',estimate_percent=>100,cascade=>true);
. Ви навіть можете побачити, що імена індексів є послідовними. Тож тепер єдина відмінність між двома таблицями полягає в тому, що перша була завантажена у випадковому порядку протягом тривалого періоду, з блоками, розкиданими на диску (у табличному просторі разом з кількома іншими великими таблицями), друга завантажувалася як одна партія ВСТАВИТЬ-ВИБІР. Крім цього, я не можу уявити ніякої різниці. (Початкова таблиця була зменшена з моменту останнього великого видалення; після цього не було жодного видалення.)
Ось плани запитів для хворих та клоніруючої таблиці (Рядки під чорною щіткою однакові по всьому малюнку, а також під сірою кистю.):
(У цьому прикладі є 1867 рядків, які починаються з чорного пензликом ідентифікатора. 2-рядовий запит створює кардинальність 1867 * 2, 3-рядовий запит створює кардинальність 1867 * 3 тощо. Не можна Будь збіг обставин, схоже, Oracle не піклується про кінець ідентифікаторів.)
Що може спричинити таку поведінку? Очевидно, було б досить дорого відтворити стіл у виробництві.
USER_TABLES: http://i.stack.imgur.com/nDWze.jpg USER_INDEXES: http://i.stack.imgur.com/DG9um.jpg Я змінив лише ім'я схеми та простору таблиць. Ви можете бачити, що назви таблиці та індексу такі ж, як на скріншоті плану запитів.