Конференция "Базы" » SELECT * FROM TABLE T WHERE (T.id = :param) OR (:param = -1) [FB 1.5/2.5]
 
  • Lexer © (03.11.10 11:16) [0]
    Добрый день.
    На досуге начал оптимизировать свои запросы, и столкнулся с неприятным поведением Firebird :(

    Задача передать параметр в запрос, и если параметр определенного значения, скажем -1 то выбирать все строки.
    Например:
    SELECT *
    FROM WARE W
    WHERE ((W.id_ware = :param) OR (:param = -1))
    Но при этом индекс по id_ware как оказалось не используется :( Вобщем нашел причину тормозов в своих процедурах. Это только маленький пример, запросы с подобными параметрами использую в в процедурах с большим телом в for select
    Нашел пока 2 варианта решения, но все они кривые:
    1. разбить на два запроса проверив сначала параметр, но при этом надо будет и дублировать и вычисления для каждого запроса :(
    т.е
    2. в данной процедуре сначала сформировать в переменную запрос в зависимости от параметра и запихнуть его в execute statement, при этом не придется дублировать вычисления, но выглядеть это будет криво.
    3. создать для запроса отдельную процедуру и в проуедуре вычислений доставть данные из неё, но данные вариант имеет два минуса: лишняя процедура, дублирование во второй процедуре тела запроса.
    Кто-нибудь сталкивался с подобными задачами? Помогите, пожалуста найти более прямой вариант. Если надо могу описать задачу подробнее.
  • Sergey13 © (03.11.10 12:07) [1]
    Как вариант
    SELECT *
    FROM WARE W
    WHERE W.id_ware between :param and :param1

    если надо все то от -1 до бесконечности, если одно значения - параметры равны
  • Lexer © (03.11.10 12:25) [2]
    Sergey13, Гениально! И главное просто и красиво! Респект и уважуха!!!
    Набросил примерчик всё работает отлично

    CREATE PROCEDURE SP_TESTIK (param INTEGER)
    AS
     DECLARE VARIABLE MaxInt INTEGER;
     DECLARE VARIABLE param2 INTEGER;
    BEGIN
     MaxInt = 2147483647; -- (2^32)-1
     IF (param IS NULL) THEN param = -1000;

     IF (param = -1000) THEN param2 = MaxInt; ELSE param2 = param;
     FOR
       SELECT W.id_ware
         FROM WARE W
        WHERE W.id_ware BETWEEN :param AND :param2
         INTO :id_ware
     DO
       BEGIN
         -- тыры пыры
         -- спасибо Сергею :)
       END
    END

  • sniknik © (03.11.10 12:58) [3]
    > Но при этом индекс по id_ware как оказалось не используется
    причина может быть в одноименных параметрах... только в BDE насколько помню так было можно. в ADO же (и др.)  одноименные не определяются по имени оба, а только один, т.е. может не использоваться id_ware а может и не сработать сравнение с -1, смотря как парсер определяющий параметры работает.

    т.е. 4 вариант - проверить с разноименными, задавать 2 значения, и не попадаться больше на эту удочку.
  • Lexer © (03.11.10 13:29) [4]
    sniknik, с одноименнными параметрами действительно были проблемы когда работал с BDE, использовал отдельный "need_all=(1,0)", но те времена прошли

    здесь как оказалось проблема в самой СУБД
    например запросы
    SELECT * FROM TABLE T WHERE T.id = :param

    - индекс используется
    SELECT * FROM TABLE T WHERE (T.id = :param) OR (1=0)

    - индекс не используется, идет чтение всех строк :(
    SELECT * FROM TABLE T WHERE 1=0

    - и в этом запросе индекс не используется, идет чтение всех строк, хотя по условию можно было бы файрбёрду догадаться что таблицу то и проверять ненадо
  • stas © (03.11.10 14:35) [5]
    sniknik ©   (03.11.10 12:58) [3]
    Да это вопрос СУБД.MSSQL так же работает.
  • Кщд (08.11.10 07:38) [6]
    >Lexer ©   (03.11.10 11:16)
    >На досуге начал оптимизировать свои запросы, и столкнулся с неприятным >поведением Firebird :(
    вполне предсказуемое поведение оптимизатора

    если переписать через union?
 
Конференция "Базы" » SELECT * FROM TABLE T WHERE (T.id = :param) OR (:param = -1) [FB 1.5/2.5]
Есть новые Нет новых   [134431   +15][b:0][p:0.001]