InterBase: тормозология и глюконавтика
Страница 38. Глюки, официально исправленные в 5.6



Глюки, официально исправленные в 5.6

  • Утечка памяти при сортировке. Оказывается, предыдущие версии в процессе длительных пересортировок записей в рамках отработки планов не всегда возвращали системе блоки памяти, взятые под сортировку. Правда, существенных перерасходов я лично не наблюдал.
  • Попытка несколько раз создать и уничтожить одну и ту же хранимую процедуру при третьей попытке приводит к обвалу сервера. Видели мы такое, и не только с процедурами. Хотелось бы надеяться, что правда сделали.
  • Использование условий с min() в операторе delete приводило к потере данных. В чём именно заключалась потеря данных, не расшифровывают. В качестве примера приводят запрос:
    delete from foo
    where ( select min(bar) from foo );
  • Длительные запросы приводили к зависанию других пользователей до завершения работы запроса. Деталей не расшифровывают. Судя по всему, нас хотят уверить, что вылечены глюки с распределением нагрузки между внутрисервеными потоками и пользовательскими соединениями. Хотелось бы верить, да вот не верится, пока сам не увижу.
  • Попытка при определении вычисляемого поля в таблице (computed by) сослаться на процедуру (то есть поле вычислялось результатом процедуры) подвешивает сервер. На самом деле попытки комбинировать процедуры и запросы во многих случаях приводит к неприятностям. Единственные исключения, без которых, пожалуй, от них вообще не было бы толку, это вызов запроса изнутри процедуры или запрос к одной единственной процедуре. В общем мораль: мухи - отдельно, котлеты - отдельно.
  • Плохо написанный триггер или хранимая процедура могут переполнить внутренний стек сервера и повесить его. На самом деле с процедурой это действительно можно, а вот с триггером. В четвёрке максимальная вложенность вызовов триггеров составляет всего 8. Как при такой глубине может что-то переполниться?... Хотя по некоторым сведениям, в interbase 5.6 глубина триггерной рекурсии может доходить до 700 и даже 1000, то есть старое ограничение сильно ослаблено. Но всё же это не повод, чтобы злоупотреблять.
  • План запроса, сгенерированный для внешних соединений не работал в версиях 4.2.1 ... 5.5. Подробности опять не разъясняют. На самом деле там дело было в том, что очевидно работоспособные и эффективные с виду планы не воспринимались interbase. Чаще всего ругань была о неприменимости индекса. Те же планы, что генерировались автоматически, обычно исполнялись нормально. По крайней мере на моей памяти. А вообще-то хорошо бы было, чтобы в этой области навели порядок - вещь нужная.
  • Исправлены функции из стандартной библиотеки (которая поставляется с пятёркой): LTRIM(), RTRIM(), LOWER().
  • Distinct может вернуть некорректное количество строк, если отрабатывается по плану, содержащему неуникальный индекс. Приводится пример:
    select distinct customer from sales s, customer c
    where s.cust_no = c.cust_no and total_value > 10000 PLAN JOIN ( C ORDER CUSTNAMEX, S INDEX (RDB$FOREIGN25) )
    Предполагается, что CUSTNAMEX неуникальный. Причём такие планы могут генерироваться и автоматически.
    Я уже писал, что distinct обрабатывается через упорядочение. А это значит, что для его реализации могут быть использованы индексы. В пятёрке видимо. Так вот оказалось, что interbase всегда ведёт себя так, будто попавшийся индекс уникальный.
  • Оптимизатор неправильно обрабатывал пары равенств на неуникальных индексах. Это приводило к разрастанию серверного процесса и иногда к зависанию.
  • Попытка уничтожить и вновь создать используемый в данный момент триггер подвешивала сервер. Ну это уж всем известно, что метаданные править нужно только при полной отключке.
  • Использование агрегатных функций на представлении, уже содержащем агрегатные функции может подвесить сервер. От приведённого ими примера я просто протащился.
    create view vw_shipping ( orderid, lag, shipvia, summation) as 
    select o.orderid, o.shipdate - o.saledate, shipvia,
    (select sum(total) from lineitem li where li.orderid = li.orderid)
    from orders o;
  • select lag, avg(summation) from vw_shipping group by lag order by lag;
    Уж сколько раз предупреждали, что селект в селекте до добра не доводит ... И в который раз уже борладовцы обещали, что это заработает. Не верю! Не делайте так никогда!
  • select count(*) из вьюшки, содержащей соединение может подвесить сервер после третьего исполнения подряд. Уууу... А интересно, хоть что-нибудь со вьюшками можно сделать БЕЗОПАСНО?
  • Одновременный коммит кучи хранимых процедур при недостатке виртуальной памяти может обрушить сервер. Давно известная мораль: обновления метаданных должны быть автокоммитными.
  • Автоматическая сборка мусора (sweep) может обрушить сервер, если попадётся таблица с метаданными, содержащими индексы по полям, допускающим значения null и незагруженные в данный момент в память. Кто не загружен - метаданные, таблицы или индексы по их формулировке не разберёшь. Но если это правда, то глюк получается интересный. Сервер должен падать сам собой без видимых причин, причём очень редко.
  • Многократное выполнение процедуры, содержащей ссылку на UDF, без коммитов между вызовами процедуры может повесить сервер. Что-то такое мы подозревали. По крайней мере у нас в Архиве, где UDF - жизненная необходимость. Пока. Но чтобы избавиться от них придётся попотеть ...
  • Left outer join может некорректно обрабатывать значения default у полей.
  • cast() может выдавать некорректные результаты. Приводят пример:
    create table t1 (f1 integer);
    create table t2 (f1 numeric(15,1));
    insert into t2 values(1.0);
    insert into t2 values(10.0);
    insert into t2 values(100.0);
    insert into t2 values(1000.0);
    commit;
    insert into t1

    select cast(f1 as integer)
    from t2;
    commit;

    select * from t1;

    F1
    ==========
    0
    1
    10
    100
  • Подумаешь, на порядок ошиблись ...
  • Обновление таблицы с полями varchar() суммарной длинной более 32 КБ может запороть базу из-за ошибок в подсчёте внутренней длинны записи. Весьма хреновая вещь, надо сказать. Мы как-то предполагали, что уж varchar() работает корректно. То есть ограничение в 32 К надо трактовать не как ограничение на длинну одного строкового поля, а на суммарную длинну записи. Хотя опять же, эти паразиты не договаривают, какая длинна имеется в виду: объявленная в метаданных или реальная длинна строк. И с заголовками (2 или 4 байта) или "в сыром виде". Тем не менее, к границам видимо лучше не приближаться.
  • Можно объявить процедуру, которая вызывает UDF с некорректным числом аргументов, после чего такая процедура будет вешать сервер, не будет альтериться или удаляться.
  • Запросы продолжают исполняться до конца даже после того, как клиент аварийно оборвал соединение. Вообще-то эта проблема давно всех доставала и похоже, что в 5.6 ей уделили наконец-то серьёзное внимание. Из другого источника стало известно, что в указанной версии в файле interbaseCONFIG появились новые параметры. О чём писалось в разделе 'Как InterBase падает'. По умолчанию эти параметры закомментированы и по-видимому это означает отсутствие контроля. Рекомендуется поставить явные значения.
  • Запрос, у которого в условии where строковое поле сравнивается с константой длинной больше, чем у поля, может обрушить сервер. Как просто!
  • Использование компонента interbaseX для получения событий от сервера нагружает процессор на 100% при закрытии соединения NetBEUI. Мораль: давно доказано, что все нормальные пользователи подключаются через TCP/IP.
  • Динамическая выгрузка gds32.dll не освобождает все ресурсы. В общем, если вы коннектитесь через BDE несколько раз, то лучше полностью перезапускать программу.
  • Validation может выругаться на испорченные индексы, если заглушить сервис interbase при активных соединениях с клиентами.
  • Скрипты со ссылками на несуществующие внешние файлы могут обрушить сервер.
  • Gds32.linterbase больше не совместим с Borland C++ Builder. Ну дают!
  • Неудачное обновление уникального ключа может запороть базу: "Statement failed, SQLCODE = -902 internal gds software consistency check (wrong record length (183)) ".
 
« Предыдущая статья