[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Укоротить запрос
Лена
Есть запрос вида:
SELECT Z.ZAKKODE, Z.ZAKDATE ... FROM Z.ZAKAZY WHERE Z.ZAKAZ IN (23,34,45,67)


Когда заказов немного, с запросом все нормально, когда их больше 500, т.е. Z.ZAKAZ IN (23,34,45,67 и т.д. - здесь длинный список) не работает.
Как можно поменять запрос, чтобы он стал короче?

Меняла так:
Z.ZAKAZ IN (SELECT ZAKAZ, SUM(KURSDIFF) FROM DVIVZAKUP WHERE (ZAKAZ>0) GROUP BY ZAKAZ HAVING SUM(KURSDIFF)<>0)

С подзапросом работает медленно. Таких конструкций с IN может в одном запросе быть несколько.

Есть еще варианты?



Спустя 26 минут, 34 секунды (21.01.2012 - 18:59) dadli написал(а):
Цитата
Меняла так:
Z.ZAKAZ IN (SELECT ZAKAZ, SUM(KURSDIFF) FROM DVIVZAKUP WHERE (ZAKAZ>0) GROUP BY ZAKAZ HAVING SUM(KURSDIFF)<>0)

С подзапросом работает медленно


странно что ето вообшем работает, так как в подзапросе два поля blink.gif

Спустя 8 минут, 37 секунд (21.01.2012 - 19:07) Лена написал(а):
там все нормально, не оттуда вырезала подзапрос.
Сам запрос большой, он из отчета, где добавляется разная фильрация по заказу, менеджерам и т.д.
Ну пусть будет так:
Z.ZAKAZ IN (SELECT ZAKAZ FROM DVIVZAKUP WHERE (ZAKAZ>0) AND KURSDIFF<>0)


Спустя 15 минут, 28 секунд (21.01.2012 - 19:23) caballero написал(а):
проиндексируйте zakaz

Спустя 41 минута, 59 секунд (21.01.2012 - 20:05) Лена написал(а):
на поле Zakaz во всех таблицах, которые участвуют в запросе, индексы стоят.

Спустя 2 часа, 3 минуты, 58 секунд (21.01.2012 - 22:09) caballero написал(а):
тогда нужно пробовать заменить IN на JOIN

Спустя 23 минуты, 25 секунд (21.01.2012 - 22:32) UnWind написал(а):
Чего то у меня от этого запроса аж волосы дыбом. blink.gif
Можно пожалуйста полную версию запроса в студию ? А мы уже подумаем и сделаем покороче.

Спустя 22 минуты, 19 секунд (21.01.2012 - 22:55) sergeiss написал(а):
Цитата (UnWind @ 21.01.2012 - 23:32)
Можно пожалуйста полную версию запроса в студию ?

Присоединяюсь к этому вопросу. У меня вообще такое подозрение, что подзапрос тут вообще не нужен, т.к. данные берутся из одной и той же таблицы. Если это так, то можно и нужно просто правильно написать условие выбора основного (и единственного запроса).

Спустя 4 минуты, 55 секунд (21.01.2012 - 22:59) UnWind написал(а):
sergeiss
У меня те же подозрения)

Спустя 18 часов, 58 минут, 46 секунд (22.01.2012 - 17:58) Лена написал(а):
Прошу отнестись с пониманием к тому, что увидите, чтобы не было соответствующих высказываний. Я исхожу из реальной ситуации - уже что есть, то есть, нужны такие исправления запроса, которые минимально затронут систему и ускорят работу.

Через JOIN я делать не могу. Объясняю почему.
Это ERP-система. Система работает с разными типами БД. Плохо получилось с Oracle. Oracle до 9 версии ANSI-join не поддерживает, после 9 - криво. Такое объяснение было получено от программистов компаний, которые пользуются системой и работают с Oracle. Так как отдельного интерфейса работы с Oracle нет, т.е. запросы идут для всех одинаковые, поэтому все соединения таблиц переносятся в WHERE.

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

Привожу кусок кода, который непосредственно касается запроса:

if(!$doporder) $doporder = 'Z.ZAKAZ';
$sql = "SELECT DISTINCT Z.ZAKAZ, F.SOKRASH AS FNAZ,
FIL.SOKRASH AS FILNAZ, SLOY.A_S1 AS SLOYNAZ,
Z.ZAKKODE, Z.ZAKDATE,
C.FIO AS CONT, M.A_S1 AS MANNAZ,
Z.TOTALSUM, Z.
$mons, Z.TOVSUMMA, V.A_S2 AS VALNAZS,
Z.TOTALSUM-Z.
$mons AS NEDOPL, Z.$mons-Z.TOVSUMMA AS DOLG,
$extra_field".",Z.OFORMLEN$dopselect ";

$sql .=" FROM UNIPROPS ZSTAT, ";
$sql .="FIRMS F, FIRMS FIL, UNIPROPS M, UNIPROPS V,
UNIPROPS SLOY, PERSONS C
$dopfrom, $TABLE Z$from1 ";
$sql .=" (Z.ZAKAZTIP = ZSTAT.PROPCNT) ";
$sql .="AND (Z.FIRMA = F.FIRMA) ";
$sql .="AND (Z.MANAGER = M.PROPCNT) ";
$sql .="AND (Z.FILIAL = FIL.FIRMA) ";
$sql .="AND (Z.COLOR = SLOY.PROPCNT) ";
$sql .="AND (Z.CONTACTER = C.PERSONA) ";
$sql .="AND (Z.VALUTA = V.PROPCNT) $dopfilter ";
$sql .="AND (Z.ZAKDATE BETWEEN ".$conn->DBDate(ReversDateStrPar($DATS));
$sql .=" AND ". $conn->DBDate(ReversDateStrPar($DATPO)).") ";
if($DONTSHOWNULLBALANCE) $sql .="AND (Z.$mons <> Z.TOVSUMMA) ";

switch($TABLE)
{
case 'ZAKUP': $tbl = "DVIVZAKUP ";
$pager->use_count = false;
break;
case 'ZAKAZY': $tbl = "DVIVZAKAZ ";
$pager->use_count = false;
break;
}

$sql .= "AND (Z.ZAKAZ IN (SELECT ZAKAZ
FROM
$tbl WHERE (ZAKAZ>0)
GROUP BY ZAKAZ HAVING SUM(KURSDIFF)<>0))
AND (Z.ZAKAZ NOT IN(SELECT DISTINCT ZAKAZ FROM DOPZAKUP WHERE CATEGORY=1842)) "
;

$sql .="ORDER BY $doporder, Z.ZAKDATE";

Спустя 1 час, 29 минут, 59 секунд (22.01.2012 - 19:28) caballero написал(а):
а целочисленных ключей нет? прямо по строчным join делаете? а что значит ANSI-join ? объединение идет по индексам если таковые имеются

Спустя 18 минут, 3 секунды (22.01.2012 - 19:46) Лена написал(а):
Все, что вы видите:
$sql .=" (Z.ZAKAZTIP = ZSTAT.PROPCNT) ";
$sql .="AND (Z.FIRMA = F.FIRMA) ";
$sql .="AND (Z.MANAGER = M.PROPCNT) ";
$sql .="AND (Z.FILIAL = FIL.FIRMA) ";
$sql .="AND (Z.COLOR = SLOY.PROPCNT) ";
$sql .="AND (Z.CONTACTER = C.PERSONA) ";
$sql .="AND (Z.VALUTA = V.PROPCNT)
это соединение по полям типа int, конечно. Первичные ключи таблиц.


ANSI-join - тот синтаксис, который мы привыкли видеть в MySQL - с INNER, OUTER и т.д. Oracle его не знает, я не специалист по Oracle, там как-то у них по-другому пишется соединение таблиц.



Спустя 15 минут, 51 секунда (22.01.2012 - 20:02) asokol написал(а):
Если у Вас есть возможность проверить запрос, то попробуйте одно из условий переделать с JOIN. Если сработает (что скорей всего), то в первую очередь замените все соответствующие условия на JOIN-ы.

Спустя 5 минут, 26 секунд (22.01.2012 - 20:08) caballero написал(а):
Цитата
Oracle его не знает, я не специалист по Oracle, там как-то у них по-другому пишется соединение таблиц.

Раньше так и было включая восьмую версию использовался плюсик вместо join
в современных версиях вроде все по стандарту.
в любом случае нужно просто написать два запроса одни вариант для оракла с его джойном второй для остальных БД
либо написать view для каждой БД (со своим синтаксисом ) а потом уже обращатся одинаково. и кода меньше будет

Спустя 13 минут, 32 секунды (22.01.2012 - 20:21) sergeiss написал(а):
Цитата (caballero @ 22.01.2012 - 21:08)
либо написать view для каждой БД (со своим синтаксисом ) а потом уже обращатся одинаково. и кода меньше будет

Подпишусь под этим вариантом. Это будет наиболее рационально.
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.