![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
SELECT ID FROM <SomeTable> WHERE ID IN (3, 7, 5, ...) [D7, IB6.x]
TheEd © (2006-02-05 05:31:00)Господа мастера, вопрос вроде банальный, но как заставить данный select сработать так, что бы полученный DataSet содержал записи именно в указанном порядке?
Подробности: БД - IB7.0, ID - ключевое поле, есть задача выбрать записи с ID = x1, x2, x3, ... xN в случайном порядке.
Прикол в том что иногда запрос срабатывает именно так как надо, а иногда "заботливо" сортирует записи по ID так как они в базе лежат! :(
Заранее благодарен!
evvcom (2006-02-07 11:48:00) [1]
> Во первых: данный способ подразумевает полный скан таблицы.
> Все предыдущие методы используют индексы, поэтому будут
> быстрее.
Не так категорично! Не всегда индексы оказываются быстрее фулскана. Если ты выбираешь более 10% записей (вроде такой порог) и не все нужные данные уже сидят в индексе, то оракловый оптимизатор никогда не выберет скан по индексу, т.к. потеря времени на физические чтения очень вероятно, окажется значительно больше потери при фулскане. Возможно, IB этого не учитывает или у него что-то построено в этом смысле не так как у оракла, но тем не менее такое категоричное заявление в этом случае, имхо, не уместно. Ну а переделав как в [18] можно и по индексу пройтись. А оракловый оптимизатор, возможно, и [16] по индексу разрулит. Надо пробовать.
sniknik (2006-02-07 11:38:00) [2]это можно переделать, взяв только идею
примерно на так (в принципе в FireBird должно работать, CASE там есть, мож синтаксис только поправить придется, а может и нет)
select
case ID
when 3 then 1
when 7 then 2
when 5 then 3
...
end as sortorder
,*
from ...
where ID IN (3,7,5,...)
order by 1
но все одно, ИМХО, это не подойдет для более менее большой последовательности, хотя должно быть уже лучше чем с union (теоретически, практикой не проверено)
atruhin (2006-02-07 11:09:00) [3]>>evvcom © (07.02.06 10:50) [16]
Во первых: данный способ подразумевает полный скан таблицы. Все предыдущие методы используют индексы, поэтому будут быстрее.
Во вторых: в IB вроде нет вложенных запросов (версию 7 незнаю), так что наверное не пройдет.
Остается временная таблица, и Union all
evvcom (2006-02-07 10:50:00) [4]с union слишком много можем сканов таблицы получить, с помощью индексов можно снизить, но физические чтения блоков все равно могут получиться больше, чем в других вариантах реализации. Может для IB это и не так, я сужу по Ораклу.
Есть еще вариант с одним сканом и без временной таблицы (опять же оракловый), хотя в IB, думаю, case тоже должен быть:
select *
from (
select
*,
case ID
when 3 then 1
when 7 then 2
when 5 then 3
...
else null
end as sortorder
from ...
)
where sortorder is not null
order by sortorder;
Polevi (2006-02-06 15:24:00) [5]гы, прям стих получился :-)
Polevi (2006-02-06 15:23:00) [6]xml универсален, кто знает тот поймет
кому нраится всюду CREATE #T втыкать - вперед, труба зовет
Виталий Панасенко (2006-02-06 10:45:00) [7]http://polesoft.da.ru- UDF (InitRandom/GetRandom)
select field1, field2,...,fieldN, getrandom(1000) fieldN+1 from table
order by fieldN+1
TheEd (2006-02-05 21:42:00) [8]определённо с временной таблицей красивее: union, если записей много будет очень тяжёл (см. sniknik © (05.02.06 13:05) [7] - он прав!)
TheEd (2006-02-05 21:34:00) [9]to sniknik
Спасибо, помогло!
atruhin (2006-02-05 16:02:00) [10]>>лучше уж OpenXml использовать
а при чем OpenXML и Firebird?
sniknik (2006-02-05 15:58:00) [11]Polevi © (05.02.06 15:46) [8]
нет, Xml я не буду использовать, однозначно, он медленнее чем с таблицей. а метод с таблицей кстати вовсе не обязывает все идентификаторы за раз передавать... (зачем бездумно следовать написаному? там всего лиш примеры)
выдержка из статьи, раздел "Фокус с Union" .... т.к. при тестировании производительности этот метод оказался значительно медленнее метода сOPENXML, который в свою очередь медленнееметода итерацийиметода со вспомогательной таблицей.
Polevi (2006-02-05 15:46:00) [12]>sniknik © (05.02.06 13:05) [7]
ну раз тебе так хочется при 50 тыс лучше уж OpenXml использовать, по другому ты все равно столько идентификаторов не передашь за раз
sniknik (2006-02-05 13:05:00) [13]ну так методы решения те же самые, и проблемы втретятся похожие... вот представь, что в последовательности "ID = x1, x2, x3, ... xN" N = к примеру 5 или хуже 50 тыс... и ??? с union не то что медленно, вообще работать не сможет (и без разници где запрос формировать, на сервере или клиенте. на клиенте даже хуже), с временной таблицей будет, и даже не особо напрягаясь.
Polevi (2006-02-05 12:54:00) [14]причем тут это, автор задал вопрос про сортировку
sniknik (2006-02-05 12:41:00) [15]Polevi © (05.02.06 12:08) [4]
> какая временная таблица, какой инкремент.. зачем
sniknik © (05.02.06 09:14) [2]
> писанины больше но работало бы быстрее на длинных последовательностях
http://www.sql.ru/articles/mssql/03060701ArraysAndListsInSQLServer.shtml#overview
Использование вспомогательной таблицыvs Фокус с использованием UNION.
Polevi (2006-02-05 12:08:00) [16]>sniknik © (05.02.06 09:14) [2]
какая временная таблица, какой инкремент.. зачем
select *, 1 as sortorder from .. where ..
union all
select *, 2 as sortorder from .. where ..
union all
select *, 3 as sortorder from .. where ..
order by sortorder
atruhin (2006-02-05 12:07:00) [17]Да точно. [2] sniknik © (05.02.06 09:14) - прав.
С union all все работает, только что проверил.
sniknik (2006-02-05 09:14:00) [18]union тоже будет сортировать, ему так "удобнее" выбирать дубликаты записей. попробовать union all, он не должен (не знаю как в IB)
вообще гарантию на порядок записей дает только ORDER BY, его я бы и использовал... в MSSQL (временная таблица с автоинкрементом и полем для внесения ID, порядок внесения будет последователен по автоинкременту... после простой JOIN на нее нужной таблице и ORDER BY по автоинкременту. писанины больше но работало бы быстрее на длинных последовательностях)
а вот с IB не знаю как.
atruhin (2006-02-05 07:13:00) [19]Ты запрос формируешь динамически?
тогда формируй через UNION
select ... from .... where ID = 3
union
select ... from .... where ID = 7
union
select ... from .... where ID = 5