-
Один запрос определяет ID, но запрос достаточно тормозной. В цикле в каждую итерацию этот запрос выполняется снова и снова. Цикл работает очень долго. У запроса есть один параметр, каждую итерацию цикла значение этого параметра меняется.
Хочется сделать так: Запрос выбирает все ID, вне зависимости от параметра, но удовлетворяющие остальным условиям. Нужно проверить результат другого запроса, вернул ли он ID, выбранные первым запросом. Если в цикле просматривать каждую запись из возвращенных вторым запросом, то это тоже будет долго. Можно ли как-то проверить, входит ли значение в набор данных, не прибегая к циклу?
Тоесть хочется примерно такого: if query1.FieldByName('ID').AsInteger in Query2.FieldByName('ID').asInteger then...
Query1 возвращает одно значение, query2 - несколько значений.
PS Понимаю, что написал сумбурно, но как-то затрудняюсь более конкретно сформулировать....
-
Locate ? Lookup ?
-
IN
-
Сделай с точностью наоборот: во второй запрос выбери ВСЕ(и сделай FetchAll). А далее: Locate.. в памяти будет работать гораздо быстрее, чем каждый раз дергать сервер.Я как-то делал подобное для MS SQl.. то же связь мастер-деталь(со своими заморочками-вычислениями).в первом варианте каждый раз "дергал" сервер.. работало несколько часов.. при чем долгих.. потом переделал: выбрал все, упорядоченное по ключу - буквально 15-19 минут(что для задачи, которую делали руками десяток-полтора человек в течении нескольких дней с ночевкой на работе - очень приемлемо.. :-) )
-
В смысле в квери1 заранее выбрать только то, что where id in select(второй запрос)
-
Спасибо, помогло Locate :o)
-
а быстрее обработку хочешь сделать?
просто в запросе к первой таблице сделать объединение со второй, т.е. по LEFT JOIN присоединить нужное поле (ID вроде), и тогда все будет в один цикл без локейтов, и обращаясь к одной выборке. ускорение гарантировано. (обработки, а вот запрос может дольше, особенно если нужных индексов нет. в общем нужно время в общем смотреть... и вот тут уже не гарантия, но скорее всего будет быстрей)
-
Мне нужно, чтобы данные вынимались и в случае совпадения, и в случае несовпадения, просто они по-разному обрабатываются. а если приджойнить таблицу, то будут в результат попадать или только те, которые совпадают, или только те, которые не совпадают... По крайней мере, если сделать это так, как я понимаю :о)
-
> [7] pavel_guzhanov © (19.11.08 15:20) > Мне нужно, чтобы данные вынимались и в случае совпадения, > и в случае несовпадения
1. In 2. Not In
-
> а если приджойнить таблицу, то будут в результат попадать > или только те, которые совпадают, или только те, которые > не совпадают... По крайней мере, если сделать это так, как > я понимаю :о)
Неправильно понимаешь.
sniknik © (19.11.08 12:26) [6] а быстрее обработку хочешь сделать?
просто в запросе к первой таблице сделать объединение со второй, т.е. по LEFT JOIN присоединить нужное поле (ID вроде), и тогда все будет в один цикл без локейтов, и обращаясь к одной выборке. ускорение гарантировано. (обработки, а вот запрос может дольше, особенно если нужных индексов нет. в общем нужно время в общем смотреть... и вот тут уже не гарантия, но скорее всего будет быстрей) Уже все написано. Если обрабатывается больше 50% данных обеих таблиц, то фулл-скан может оказаться быстрее, чем по индексам.
-
В Firebird забудь по IN. Навсегда. Потому, как если в SELECT в условии WHERE будет IN, то подзапрос будет выполняться на каждой записи мастер-запроса. В Firebird для этого придуман такой фокус: 1) Данные IN (обычно это список ID из другой таблицы) выбираются один раз в строку, значения которой разделены разделителями. Например, символом "~", в виду его редкоупотребляемости на практике. Запрос делается один раз. 2) По мастер таблице делается запрос, в условии которго сказано: WHERE (:PMY_VALUES CONTAINING '~'||МастерТаблица.Поле||'~'). Тогда подзапрос не срабатывает на каждой записи, что влечет экспоненциально увеличение производительности, особенно на больших объемах данных. Другой вопрос - реализация. На Firebird1.5 - однозначно через хранимую процедуру, на Firebird 2.0 и выше можно через PSQL блок. Например: Firebird 1.5
CREATE PROCEDURE MY_PROC(
MY_VAL INTEGER
....
)RETURNS(
....
)AS
DECLARE VARIABLE P_VALS VARCHAR(32000);
DECLARE VARIABLE P_VALUE INTEGER;
BEGIN
P_VALS = '~';
FOR
SELECT T1.ID FROM MY_TABLE1 T1 WHERE (T1.FIELD = MY_VAL)INTO :P_VALUE
DO
IF(:P_VALUE IS NOT NULL)THEN
P_VALS = :P_VALS || :P_VALUE || '~';
FOR
SELECT ...
FROM MY_TABLE2 T2
WHERE (.....)
AND (:P_VALS LIKE '~'||T2.SOME_FIELD||'~')
INTO :....
DO
SUSPEND;
END Firebird 2.0 EXECUTE BLOCK( или
CREATE OR ALTER PROCEDURE MY_PROC(
MY_VAL DOMN$INTEGER = ?MY_VAL
....
)RETURNS(
....
)AS
DECLARE VARIABLE P_VALS DOMN$BLOB_TEXT;
BEGIN
SELECT '~'||LIST(T1.ID)||'~'
FROM MY_TABLE1 T1
WHERE (T1.FIELD = MY_VAL)
INTO :P_VALS;
FOR
SELECT ...
FROM MY_TABLE2 T2
WHERE (.....)
AND (:P_VALS CONTAINING '~'||T2.SOME_FIELD||'~')
INTO :....
DO
SUSPEND;
END
-
> Потому, как если в SELECT в условии WHERE будет IN, то подзапрос будет выполняться на каждой записи мастер-запроса. какие страшные вещи вы рассказываете, надеюсь это сказка... ибо если не так, то из-за одного этого нужно бросать Firebird раз и навсегда. можно привести план выполнения для вот такого примерно запроса с IN, SELECT * FROM Table1 t1 WHERE t1.ID IN (SELECT t2.Reft1ID FROM Table2 t2 WHERE t2.ID=2) просто убедиться. надеюсь понятно из в запросе, что на что ссылается. к плану желателен реально выполняемый запрос, для гарантии что ничего не перепутано (например в подзапрос для расчетов/сравненй не попали записи из главной таблицы).
|