Почему Sybase не использует функциональный индекс?
Я создал функциональный индекс для таблицы Sybase.
create index acadress_codpost_lower on acadress(LOWER(l5_codpost))
Затем я запускаю сложный запрос, который использует индекс. Без индекса это занимает 17.086 секунд. С индексом это занимает 0,076 секунды.
Я запускал его на двух разных клиентах SQL, а также на серверах разработки и предварительной разработки Sybase. Во всех случаях вижу ускорение от индекса.
Однако когда мы запускаем идентичный запрос из Java (и я знаю, что он идентичен, так как я зарегистрировал сгенерированный SQL и использовал его непосредственно в клиентах SQL), тогда производительность будет точно такой же, как и до того, как мы добавили индексы.
Какая возможная причина может быть для идентичных запросов SQL, чтобы использовать индекс при запуске из ACE и SQuirreL, но не из Java?
Сначала я подумал, что, возможно, Sybase кэширует планы выполнения для подготовленных операторов и не использует индекс. Мы пытались перезапустить сервер Java несколько раз (другие службы используют сервер Sybase, поэтому отказов труднее), и это не имело никакого значения.
Другая возможность заключается в том, что мы используем очень старую версию драйвера Sybase:
jConnect (TM) for JDBC(TM)/7.00(Build 26502)/P/EBF17993/JDK16/Thu Jun 3 3:09:09 2010
Возможно ли, что функциональные индексы не поддерживаются этой версией JConnect?
Кто-нибудь знает, может ли быть правильной какая-либо из этих теорий или есть что-то еще, что я пропустил?
1 ответ
Я изучал это время от времени в течение прошлой недели или около того, и хотя у меня все еще нет окончательного ответа, у меня есть правдоподобная теория.
Я попробовал предложения из комментариев, и благодаря им я смог сузить причину до одного изменения, если у меня есть запрос:
"where LOWER(aca.l5_codpost) like '"+StringEscapeUtils.escapeSql("NG179GT".toLowerCase())+"'"
Затем запрос использует индекс и возвращается очень быстро.
Если с другой стороны у меня есть:
where LOWER(aca.l5_codpost) like :postcode
query.setString("postcode", "NG179GT".toLowerCase());
Тогда он не использует индекс.
Теория заключается в том, что Sybase оптимизирует план запросов без информации о содержимом :postcode
, поэтому он не использует индекс. Он не перекомпилирует запрос, когда узнает содержимое, поэтому никогда не использует индекс.
Я пытался заставить индекс с помощью (index acadress_codpost_lower)
и это не имело никакого значения.
я пробовал set forceplan off
а также set literal_autoparam off
и ни один не имел никакого значения.
Единственное, что я могу найти, что изменяет поведение, - это непосредственно встраивать опцию в план запроса по сравнению с ее наличием в качестве параметра.
Поэтому обходной путь - встраивание параметра в строку запроса, хотя я все еще хотел бы знать, что на самом деле происходит, и правильно решить проблему.