Почему изменение предложения where по этим критериям так резко сокращает время выполнения? - PullRequest
2 голосов
/ 23 марта 2012

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

Проблемный запрос:

SELECT *
FROM
  (SELECT ah.*,
    com.location,
    ha.customer_number,
    d.name applicance_NAME,
    house.name house_NAME,
    dr.name RULE_NAME
FROM actionhistory ah
INNER JOIN community com
ON (t.city_id = com.city_id)
INNER JOIN house_address ha
ON (t.applicance_id   = ha.applicance_id
AND ha.status_cd = 'ACTIVE')
INNER JOIN applicance d
ON (t.applicance_id = d.applicance_id)
INNER JOIN house house
ON (house.house_id = t.house_id)
LEFT JOIN the_rule tr
ON (tr.the_rule_id = t.the_rule_id)
WHERE actionhistory_id    >= 'ACT100010000' 
ORDER BY actionhistory_id
)
WHERE rownum <= 30000;

Исправление

SELECT *
FROM
  (SELECT ah.*,
    com.location,
    ha.customer_number,
    d.name applicance_NAME,
    house.name house_NAME,
    dr.name RULE_NAME
FROM actionhistory ah
INNER JOIN community com
ON (t.city_id = com.city_id)
INNER JOIN house_address ha
ON (t.applicance_id   = ha.applicance_id
AND ha.status_cd = 'ACTIVE')
INNER JOIN applicance d
ON (t.applicance_id = d.applicance_id)
INNER JOIN house house
ON (house.house_id = t.house_id)
LEFT JOIN the_rule tr
ON (tr.the_rule_id = t.the_rule_id)
WHERE actionhistory_id    >= 'ACT100010000' and  actionhistory_id  <= 'ACT100030000'
ORDER BY actionhistory_id
)

Все столбцы _id являются индексированными последовательностями. План объяснения первого запроса стоил 372, а второй - 14. Он выполняется в базе данных Oracle 11g.

Кроме того, если actionhistory_id в предложении where меньше чем ACT100000000, исходный запрос возвращается немедленно.

Ответы [ 2 ]

3 голосов
/ 23 марта 2012

Это связано с индексом столбца actionhistory_id.

Во время первого запроса Oracle должна вернуть все блоки индекса, содержащие индексы для записей, которые идут после 'ACT100010000', затем она должна сопоставить индекс с таблицей, чтобы получить все записи, а затем она извлекает 29999 записей из набор результатов.

Во время второго запроса Oracle должен только возвращать блоки индекса, содержащие записи между «ACT100010000» и «ACT100030000». Затем он извлекает из таблицы те записи, которые представлены в индексных блоках. На этом шаге сбора записи после того, как найден индекс, гораздо меньше работы, чем при использовании первого запроса.

Замечание вашей последней строки о том, что идентификатор меньше ACT100000000 - звучит для меня, что все эти записи могут быть в одном блоке памяти (или в непрерывном наборе блоков).

РЕДАКТИРОВАТЬ: Пожалуйста, также подумайте, что сказал Джастин - я говорил о фактической производительности, но он указывает, что идентификатор, являющийся varchar, значительно увеличивает потенциальные значения (в отличие от числа) и что предполагаемый план отражать большее время, чем реальность, потому что оптимизатор не знает весь диапазон до выполнения. Для дальнейшей оптимизации, учитывая его точку зрения, вы можете поместить индекс на основе функции в столбец id или сделать его комбинированным ключом с частью varchar в одном столбце и числовой частью в другом.

1 голос
/ 23 марта 2012
  • Каковы планы обоих запросов?
  • Актуальна ли статистика в ваших таблицах?
  • Возвращают ли два запроса один и тот же набор строк?Не очевидно, что они делают, но, возможно, ACT100030000 является самым большим actionhistory_id в системе.Это также немного сбивает с толку, потому что первый запрос имеет предикат actionhistory_id со значением TRA100010000, которое сильно отличается от значения ACT во втором запросе.Я предполагаю, что это опечатка?
  • Вы измеряете время, необходимое для извлечения первого ряда?Или время, необходимое для получения последнего ряда?Каковы эти истекшие времена?

Я полагаю, что без этой информации тот факт, что вы используете неверный тип данных для столбца actionhistory_id, влияет на способность оптимизатора Oracle генерировать соответствующую мощностьоценки, которые, вероятно, приводят к тому, что оптимизатор недооценивает избирательность ваших предикатов и генерирует плохо выполняемые планы.Человек может догадаться, что actionhistory_id - это строка, которая начинается с ACT10000, а затем имеет 30000 последовательных числовых значений от 00001 до 30000, но оптимизатор не настолько умен.Он видит строку из 13 символов и не может понять, что последние 10 символов всегда будут числами, поэтому есть только 10 возможных значений, а не 256 (при условии 8-битных символов), и что первые 8 символов всегдабудет то же самое постоянное значение.Если, с другой стороны, actionhistory_id был определен как NUMBER и имел значения от 1 до 30000, оптимизатору было бы значительно проще делать разумные оценки селективности различных предикатов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...