Поиск  Пользователи  Правила 
Закрыть
Логин:
Пароль:
Забыли свой пароль?
Войти
 
Страницы: 1
RSS
Выборка одной записи
 
Есть таблица, содержащая около 500 000  записей. Среди них, аккуратно разбросано около 100 000 записей удовлетворяющих некоторому условию, говорящему о том, что запись должна быть обработана. Эти записи должны быть извлечены по одной.
Не мудурствуя лукаво, я написал запрос:

Код
SELECT Min(nPayments_Id) FROM vw_sspDischargePaymentId 
WHERE 
(nStatus_Id = 9  OR nStatus_Id = 8 OR nStatus_Id = 19  OR nStatus_Id = 11 OR (nStatus_Id = 3 ) OR 
nStatus_Id = 22 OR nStatus_Id = 20 OR (nStatus_Id = 18 )) AND 
(nTrGroup_Id = 2 OR nTrParent_Id = 2) 


Все работает, все счастливы, вот только при исполнении в MSSQL этот запрос работает 1574 мс, а в ORACLE 2632 мс.
Причем реально по условию работы, мне нет необходимости искать именно MIN, мне нужна любая запись, удовлетворяющая условию.

Ради экспиремента поправил запрос, написав:
Код
SELECT TOP 1 nPayments_Id FROM vw_sspDischargePaymentId 
WHERE 
(nStatus_Id = 9  OR nStatus_Id = 8 OR nStatus_Id = 19  OR nStatus_Id = 11 OR (nStatus_Id = 3 ) OR 
nStatus_Id = 22 OR nStatus_Id = 20 OR (nStatus_Id = 18 )) AND 
(nTrGroup_Id = 2 OR nTrParent_Id = 2) 


Время работы на MSSQL составило 141 мс!!!!

Понятно, что ORACLE такую фичу не держит.  Нарыл ORACL-евую фичу  "ROW_NUMBER() OVER ". Результаты не утешительны. Я так понимаю, что они связаны с тем, что ORACLЕ все-таки строит полный рекордсет, а потом отбрасывает лишнее.

Господа, выручайте!!! Нужна конструкция, которая будет  работать и в MSSQL и в ORACLE. Желательно с эффективностью "TOP 1".
 
А у тебя индексы есть? Если есть то напиши какие именно и по каким полям
 
Цитата
real_maverick пишет:
А у тебя индексы есть?
Да, безусловно.

vw_sspDischargePaymentId - это вьюшка.
Она включает три таблицы. Все проиндексированы по одному полю.
Первая по nPayments_Id (эта таблица как раз и содержит 500 000 записей) - совершенные платежи.
Вторая таблица по nTerminal_Id - (содержит около 50 записей, и связана с предыдущей связью многие к одному) - терминал, на котором был соверен платеж.
Третья таблица по nTrGroup_Id - ( содержит около 20 записей и опять связана с предыдущей связью многие к одному) - группа, в которую входит терминал, на котором совершен платеж.

Запрос призван отобрать платежи определенных статусов, для определенной группы.

Тонкий момент, помимо того, что терминалы входят в группы, группы также входят друг в друг, образуя дерево. Запрашивая результаты для родителя, я одновременно запрашиваю результаты и для всех его детей. Таким образом, если транзакция вополнена на "ребенке", она булет считаться выполненной и на "родителе". Средняя глубина вложенности - 3-4 записи. Следовательно оригинальные записи о платежах "размножаются", и в результирующей вьюшке присутсвуют несколько раз - отдельно для каждой группы входящей в выбираемую ветку дерева.Результирующее число записей возвращаемое вьюшкой без фильтрующего условия около 1 800 000 (еще раз напомню, число уникальных записей около 500 000).

Позволю себе еще раз сформулировать свой вопрос:
Существует ли конструкция воспринимаемая и MS SQL и ORACLE, грубо говоря, "стандартная" конструкция TSQL, позволяющая получить мне одну любую запись  удовлетворяющую условию, без построения полного рекордсета?
 
В оракле есть ROWNUM
SELECT ... FROM ...
WHERE ... AND ROWNUM =1
 
Michael : спасибо за совет. Я попробовал. К сожалению, результаты (время исполнения) не изменились.
 
Цитата
Анатолий пишет:
Код

SELECT Min(nPayments_Id) FROM vw_sspDischargePaymentId
WHERE
(nStatus_Id = 9  OR nStatus_Id = 8 OR nStatus_Id = 19  OR nStatus_Id = 11 OR (nStatus_Id = 3 ) OR
nStatus_Id = 22 OR nStatus_Id = 20 OR (nStatus_Id = 18 )) AND
(nTrGroup_Id = 2 OR nTrParent_Id = 2)

А если переделать запрос так:

Код
SELECT nPayments_Id FROM vw_sspDischargePaymentId 
WHERE 
nStatus_Id IN ( 9 , 8, 19, 11, 3, 22, 20, 18 ) AND (nTrGroup_Id = 2 OR nTrParent_Id = 2) AND ROWNUM=1

Не быстрее будет?

Или так:

Код
SELECT nPayments_Id FROM vw_sspDischargePaymentId 
WHERE 
nStatus_Id IN ( 9 , 8, 19, 11, 3, 22, 20, 18 ) AND (nTrGroup_Id = 2 OR nTrParent_Id = 2) 
GROUP BY nPayments_Id
 
если тебе не пугает жесткая привязка именно к oracle то смотри на иерархические запросы connect by, должно помочь.
У m$sql кстати есть забавная фича, он строит индексы внутренние по каким то своим критериям практически для всех колонок в entity, причем из каких то своих соображений, думаю выигрыш в производительности кроется в этих магических индексах, которых в честном оракле ты не строил, но это не более чем фантазии.
А реально смотри конечно иерархические запросы, они бывают разные и думаю чем то поможет.
 
Что бы проще было искать - я тебе из док по ораклу пару самплов кину:

SELECT employee_id, last_name, manager_id
  FROM employees
  CONNECT BY PRIOR employee_id = manager_id;


SELECT last_name, employee_id, manager_id, LEVEL
     FROM employees
     START WITH employee_id = 100
     CONNECT BY PRIOR employee_id = manager_id
     ORDER SIBLINGS BY last_name;


SELECT last_name "Employee",
  LEVEL, SYS_CONNECT_BY_PATH(last_name, '/') "Path"
  FROM employees
  WHERE level <= 3 AND department_id = 80
  START WITH last_name = 'King'
  CONNECT BY PRIOR employee_id = manager_id AND LEVEL <= 4;


SELECT name, SUM(salary) "Total_Salary" FROM (
  SELECT CONNECT_BY_ROOT last_name as name, Salary
     FROM employees
     WHERE department_id = 110
     CONNECT BY PRIOR employee_id = manager_id)
     GROUP BY name;
 
слух ;-) только что заметил -  nTrGroup_Id - это не идентификатор транковой группы???
и компания название которой Tel (по моему) тебе не близка??? ;-))) Ну и не биллинг ли это по vo-ip?? ;-))))
 
Цитата
real_maverick пишет:
слух  только что заметил - nTrGroup_Id - это не идентификатор транковой группы???
и компания название которой Tel (по моему) тебе не близка??? )) Ну и не биллинг ли это по vo-ip?? )))
Нет, нет .... нет ....  :)

За совет спасибо ... вникаю, пробую ....
 
Попробуй хинт /*+ FIRST_ROWS(n) */

Цитата
FIRST_ROWS(n)
The hints FIRST_ROWS(n) (where n is any positive integer) or FIRST_ROWS instruct Oracle to optimize an individual SQL statement for fast response. FIRST_ROWS(n) affords greater precision, because it instructs Oracle to choose the plan that returns the first n rows most efficiently. The FIRST_ROWS hint, which optimizes for the best plan to return the first single row, is retained for backward compatibility and plan stability.
Страницы: 1
Читают тему