Привет народ.

Сто лет молчал хочется сказать. Накипело.

Прошу не голословно писать, а только по поводу. ЛУЧШЕ (ДА, НЕТ или может так)
Если нечего сказать по сути лучше промолчать.
И ТОЛЬКО ПО ПРОЧТЕНИИ ВСЕГО В ЦЕЛОМ.

Думаю у кого мелкие запросы моя мысль не заинтересует. А вот у кого огромные процедуры с множеством условий, которые хотелось хоть как то ускорить заинтересуются. Хотя я уже разочарован давно в этом мире и пишу для себя всякие хитрушки упрощающие жизнь.

То что здесь приводится это упрощенный вариант для наглядности на самом деле условие в WHERE намного больше и сложней.
К примеру (0-все организации, 1 только выбранные, 2 кроме выбранных)
   ((:AD500_6 = 0) or
(:AD500_6 = 1 and EXISTS(SELECT * FROM D503 WHERE D503.D500_1 = :AD500_1 and D503.D009_1 = T003.D009_1b)) or (:AD500_6 = 2 and not EXISTS(SELECT * FROM D503 WHERE D503.D500_1 = :AD500_1 and D503.D009_1 = T003.D009_1b)) )

Сначала начал пользоваться EXECUTE STATEMENT в 2 - 3 местах. Но потом воткнул еще в несколько. А уж когда появилась возможность
EXECUTE STATEMENT (...) (и тут параметры)
я быстренько переписал запросы.

Но вся радость закончилась когда я написал, что то подобное этому:
EXECUTE STATEMENT
('SELECT cast(:X as int) FROM RDB$DATABASE')
(x := :x, y := :y)
не заметившим или не знающим объясняю параметр ":y" не участвует в запросе и получаем крик от сервера.

Поняв, что затея заменить часть запросов не удалась из за громоздкости реализации я остановился на том что уже использую.

И вот наткнулся на довольно простенький зарос который оказалось только в периоде 1-го дня почему то делает более 36000 чтений из таблицы документы. У очень маленькой организации (База за несколько лет всего 270 Мб, работают с документами). Я давай рыть и отписался ДЯ и он вот это разъяснил

(:NextID = T003_1) or
   (:NextID IS NULL and
    (:I_IDDOC = T003.IDDoc or :I_IDDOC IS NULL) and
    T003_3 >= :I_FD and T003_3 <= :I_TD and
    (D009_1 = :I_D009_1 or D009_1b = :I_D009_1) )
занчение в NextID 100% есть получаем 12000 чтений

как всегда быстро сказал, что к чему. Оказывается сервер все, что после (:NextID = T003_1) or не совсем понимает, что это условие всегда FALSE и лопатит по записям хотя я считал что скобки с :NextID IS NULL дадут ему понять что условие не выполнимо.
Это получается тоже как бы не фонтан по сути.
   ((:AD500_6 = 0) or
    (:AD500_6 = 1 and EXISTS(...)) or
    (:AD500_6 = 2 and not EXISTS(...)) )
Настроение упало ниже плинтуса ибо все запросы в отчетах так и построены в которых "(или или или) и (или или или) и (или или или) и (или или или) и (или или или) и (или или или)"
Мне разработчики говорят мол идиотские запросы у тебя.
А теперь объясните как описать такое:
Немного вникнем в тему клиент говорит я хочу реестр
товар, кол-во, сум
я кричу, а это просто и тут поражаюсь количеству вариаций. При условии выбора
1.Нужно выбрать нашу или несколько наших организаций по которым дать
результат "тут просто join"
2.Теперь хочу указать склады (все или по всем или кроме выбранных)
3.Теперь хочу указать кладовщики (все или по всем или кроме выбранных)
4.Теперь хочу указать клиенты (все или по всем или кроме выбранных)
5.Теперь хочу указать типы документов (все или по всем или кроме выбранных)
6.Теперь хочу указать товары (все или по всем или кроме выбранных)
как здесь сделать UNION или JOIN дабы никого не обидеть с условием
"(или или или) и (или или или) и (или или или) и (или или или) и (или или или) и (или или или)"

ТАК ВОТ после того как Vlad Khorsun мне сказал это не кому не интересно иди в конфу я пришел сюда узнать надо оно или нет. Что бы ускорить запрос я его переписал и получил на 17640 чтений меньше вместо 36680 всего 19040

БЫЛО
 SELECT COUNT(*) FROM T003 WHERE
   (:I_ID IS NOT NULL and (:I_ID = T003_1 or :I_ID = T003_1b)) or
   (:I_ID IS NULL and
    (:I_IDDOC = T003.IDDoc or :I_IDDOC IS NULL) and
    T003_3 >= :I_FD and T003_3 <= :I_TD and
    (D009_1 = :I_D009_1 or D009_1b = :I_D009_1) )
   for update
 INTO :F_COUNT;

СТАЛО
тут не КРИЧАТЬ ибо после этого делается тоже тело но с FOR EXECUTE STATEMENT первый надо было для оценки времени выполнения. В теле FOR EXECUTE STATEMENT масса вызовов процедур. Я понимаю, что можно начать разбивать на массу процедурок тело, потом кучу раз написать циклы вызывать это дробленое безобразие. Потом не один пионер не разберется, что я написал. Ладно смотрим, что же получилось:
 sSQL = '';
 if (I_ID IS NOT NULL) then begin
   sSQL = sSQL || ' (:I_ID = T003_1 or :I_ID = T003_1b) ' ||
    ' and :I_IDDOC IS NULL' ||
    ' and cast(:I_FD as DATE) is not distinct from cast(:I_FD as DATE)' ||
    ' and cast(:I_TD as DATE) is not distinct from cast(:I_TD as DATE)' ||
' and cast(:I_D009_1 as varchar(38)) is not distinct from cast(:I_D009_1 as varchar(38))';
 end else begin
   sSQL = sSQL || ' :I_ID is null';
   if (I_IDDOC IS NOT NULL)
     then sSQL = sSQL || ' and :I_IDDOC = T003.IDDoc';
     else sSQL = sSQL || ' and :I_IDDOC is null';
   sSQL = sSQL || ' and T003_3 >= :I_FD and T003_3 <= :I_TD' ||
    ' and (D009_1 = :I_D009_1 or D009_1b = :I_D009_1) ';
 end
 EXECUTE STATEMENT
 ('SELECT COUNT(*) FROM T003 WHERE ' || sSQL || ' for update')
(I_ID := :I_ID, I_IDDOC := :I_IDDOC, I_FD := :I_FD, I_TD := :I_TD, I_D009_1 := :I_D009_1)
 INTO :F_COUNT;

Как видим наглядность потерялась  уже на очень простом запросе.

НУ А ТЕПЕРЬ ХОТЕЛКА ну почему бы не разрешить пусть даже с написанием какого ни будь командного слова мол игнорировать лишние параметры тогда все будет так
 sSQL = '';
 if (I_ID IS NOT NULL) then begin
   sSQL = sSQL || ' (:I_ID = T003_1 or :I_ID = T003_1b) '
 end else begin
   sSQL = sSQL || ' :I_ID is null';
   if (I_IDDOC IS NOT NULL)
     then sSQL = sSQL || ' and :I_IDDOC = T003.IDDoc';
   sSQL = sSQL || ' and T003_3 >= :I_FD and T003_3 <= :I_TD' ||
    ' and (D009_1 = :I_D009_1 or D009_1b = :I_D009_1) ';
 end
 EXECUTE STATEMENT
 ('SELECT COUNT(*) FROM T003 WHERE ' || sSQL || ' for update')
(I_ID := :I_ID, I_IDDOC := :I_IDDOC, I_FD := :I_FD, I_TD := :I_TD, I_D009_1 := :I_D009_1)[тут игнор их]
 INTO :F_COUNT;

P.S. Часть запросов с легкость преобразуется в читабельный.
Например
   ((:AD500_6 = 0) or
с легкостью я смогу преобразовать в то, что надо и параметры как бы на месте остаются это не вопрос. Беда заключается в других частях например если сейчас не надо учитывать "I_TD" то придется добавить конструкцию.
    ' and cast(:I_TD as DATE) is not distinct from cast(:I_TD as DATE)' ||
короче заморочки с лишними параметрами и их типами :(.

Ответить