определить позицию строки в запросе
От: ov  
Дата: 28.08.09 13:17
Оценка:
вопрос к тем, кто показывает много данных в таблицах
есть у меня запрос
SELECT Id, ....
FROM ... WHERE .... ORDER BY ...

задача — узнать каким номером будет идти строка с Id=N

по специфике приложения, должна использоваться встроенная БД, я смотрел SQLite, FireBird, MS SQL CE — нигде этого сделать нельзя кроме как полным "выкачиванием" результатов и ручным поиском.

в полноценной версии MS SQL SERVER 2005 вроде есть ROW_NUMBER(), при помощи которой это делается.

а как быть с более простыми базами, есть идеи?

зачем все это надо: чтобы в гриде с сортировкой и фильтрацией восстановить выделенную строчку после смены сортировки. так как записей может быть много, то чтение идет кусками и хотелось бы сразу прочитать нужный кусок.
Re: определить позицию строки в запросе
От: KRA Украина  
Дата: 28.08.09 13:34
Оценка:
Здравствуйте, ov, Вы писали:

ov>а как быть с более простыми базами, есть идеи?



Есть идея, как можно в firebird попытаться проэмулировать rownum. Можно попытаться использовать для этого последовательности, приблизительно так

create sequence temp_seq;
select gen_id(temp_seq,1) rownum from ....

Тут правда возникают другие проблемы, которые нужно ещё подумать как решить
1. недопущение использования одной последовательности в паралельных запросах
2. превышение максимального значения в последовательности (я не уверен, как оно устроено в firebird. вероятно, начнётся опять с нуля(?))
Re[2]: определить позицию строки в запросе
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 28.08.09 15:42
Оценка:
Здравствуйте, KRA, Вы писали:

ov>>а как быть с более простыми базами, есть идеи?


KRA>Есть идея, как можно в firebird попытаться проэмулировать rownum. Можно попытаться использовать для этого последовательности, приблизительно так


Поправки для FB.

KRA>create sequence temp_seq;



CREATE GENERATOR TEMP_GEN;
SET GENERATOR TEMP_GEN TO 0;
COMMIT;


KRA>select gen_id(temp_seq,1) rownum from ....


Угу.

KRA>Тут правда возникают другие проблемы, которые нужно ещё подумать как решить

KRA>1. недопущение использования одной последовательности в паралельных запросах

Генераторы в FB работают вне контекста транзакций, поэтому при параллельной работе придется делать по генератору на каждый запрос. Потом — удалять. Т.к. пользователь будет владельцем обьекта — все должно пройти нормально (не будет накладок с правами).

KRA>2. превышение максимального значения в последовательности (я не уверен, как оно устроено в firebird. вероятно, начнётся опять с нуля(?))


В FB 2.x генераторы — INT64. Должно хватить по уши. Насчет установки начального значения — смотри выше.

P.S. Более универсальное решение для FB — ххранимая процедура:

  I=0;
  for SELECT ... FROM ... WHERE ...
      INTO ....
  do BEGIN
       I=I+1;
       SUSPEND;
     END
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[3]: определить позицию строки в запросе
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 28.08.09 15:45
Оценка:
Здравствуйте, DarkMaster, Вы писали:

DM>P.S. Более универсальное решение для FB — ххранимая процедура:


Забыл еще про EXECUTE BLOCK;

execute block
returns (AROWNUM INT64, AVALUE varchar(10))
as
begin
  AROWNUM=0; 
  for select VALUE 
      from MYTABLE
      where VALUE LIKE 'A%'
      order by VALUEDATE
      into :AVALUE
  do begin
       AROWNUM=AROWNUM+1;
       suspend;
     end
end
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re: определить позицию строки в запросе
От: MasterZiv СССР  
Дата: 29.08.09 06:47
Оценка:
ov пишет:



> зачем все это надо: чтобы в гриде с сортировкой и фильтрацией

> восстановить выделенную строчку после смены сортировки. так как записей
> может быть много, то чтение идет кусками и хотелось бы сразу прочитать
> нужный кусок.


Какая разница, какой по порядку идёт нужная вам строка ?
У каждой строки есть первичный ключ (должен быть, иначе
нужно делать редизайн БД), вы до смены сортировки запоминаете значение
ключа, делаете сортировку, и находите нужную запись по запомненному
значению ключа.
Posted via RSDN NNTP Server 2.1 beta
Re: определить позицию строки в запросе
От: MasterZiv СССР  
Дата: 29.08.09 06:48
Оценка:
ov пишет:

так как записей
> может быть много, то чтение идет кусками и хотелось бы сразу прочитать
> нужный кусок.

А это сделать не получится.
Posted via RSDN NNTP Server 2.1 beta
Re[2]: определить позицию строки в запросе
От: ov  
Дата: 29.08.09 08:50
Оценка:
>вы до смены сортировки запоминаете значение ключа, делаете сортировку, и находите нужную запись по запомненному
>значению ключа.
все бы хорошо, да надо читать блоками. для чтения целиком проблем нет — все так и делается и прекрасно работает.

>> может быть много, то чтение идет кусками и хотелось бы сразу прочитать нужный кусок.

MZ>А это сделать не получится.
прочитать кусок не проблема. SQLite и FireBird позволяют в SELECT'е указать "окно". MS SQL CE, правда, не позволяет, но его старший брат может.
по моим тестам чтение 20К записей (на SQLite) не тормозит и можно читать целиком, но если записей будет 100К?

я отдаю себе отчет, что негоже юзеру показывать 100К записей, но в этом суть программы: длинный список с сортировкой и фильтрацией.
Re[3]: определить позицию строки в запросе
От: MasterZiv СССР  
Дата: 29.08.09 16:22
Оценка:
ov пишет:

> прочитать кусок не проблема. SQLite и FireBird позволяют в SELECT'е

> указать "окно". MS SQL CE, правда, не позволяет, но его старший брат может.
> по моим тестам чтение 20К записей (на SQLite) не тормозит и можно читать
> целиком, но если записей будет 100К?

Какими такими блоками ?
Если речь о всяких там LIMIT-ах или TOP-ах,
то их не имеет смысла применять, если вам нужны не
первые N записей.
Posted via RSDN NNTP Server 2.1 beta
Re[4]: определить позицию строки в запросе
От: ov  
Дата: 30.08.09 04:38
Оценка:
MZ>Если речь о всяких там LIMIT-ах или TOP-ах,
да, о них.
MZ>то их не имеет смысла применять, если вам нужны не первые N записей.
почему? в SQLite есть конструкция LIMIT 100 OFFSET 1000, которая вернет 100 строк с 1000-й позиции. в FireBird есть FIRST/SKIP, кажется.

и как тогда "правильно" считать результат запроса в 100К строк? за раз чтоли??
Re[5]: определить позицию строки в запросе
От: MasterZiv СССР  
Дата: 31.08.09 06:55
Оценка:
ov пишет:

> MZ>Если речь о всяких там LIMIT-ах или TOP-ах,

> да, о них.
> MZ>то их не имеет смысла применять, если вам нужны не первые N записей.
> почему? в SQLite есть конструкция LIMIT 100 OFFSET 1000, которая вернет
> 100 строк с 1000-й позиции. в FireBird есть FIRST/SKIP, кажется.

Потому что LIMIT-ы или TOP-ы в общем случая обрабатывают
сначала ВЕСЬ набор данных, а потом возвращают только его часть.
Экономия -- только на операции FETCH на клиента.

При этом экономии можно достичь только :

0) выбирая только N записей от начала набора данных,
при этом оптимизатор может понять, что от запроса нужно только
первые N строк, и построит план так, чтобы только они обрабатывались,
и то при этом нужно, чтобы операция ORDER BY оптимизировалась за счёт индекса,
а не производилась реальная сортировка, иначе опять-таки будет обрабатываться
весь потенциальный набор данных

1) выбирая N записей начиная с M-ой СУБД придётся обработать подобным же
образом M+N записей, на M записей получится экономия только на FETCH-е на
клиента, и на ещё (размер таблицы — (M+N)) -- может быть экономия, как
в случае (0)


> и как тогда "правильно" считать результат запроса в 100К строк? за раз

> чтоли??

Нужно не питать иллюзий, что есть какой-то магический способ выборки части
набора данных из всего набора. Набор нужно обрабатывать целиком.
Единственный реальный способ оптимизации выборки -- это отбросить
невыбранную часть данных, он работает (почти) всегда и везде.
Но даже в этом случае СУБД может обрабатывать весь большой невыбираемый
набор данных.

Да, вы тут говорили о SQL Lite, возможно, есть какие-то специфичные
для него аспекты этой проблемы, я его к сож. не знаю.
Posted via RSDN NNTP Server 2.1 beta
Re[6]: определить позицию строки в запросе
От: ov  
Дата: 31.08.09 09:35
Оценка:
MZ>Нужно не питать иллюзий, что есть какой-то магический способ выборки части
MZ>набора данных из всего набора. Набор нужно обрабатывать целиком.
да не в иллюзиях дело. просто хочется решить вопрос на уровне БД, оптимальным для нее способом. чтобы я мог ей сказать "хочу такие-то записи, с такой-то позиции", а она уже сама думала как их мне наиболее оптимально выдать.

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

MZ>Да, вы тут говорили о SQL Lite, возможно, есть какие-то специфичные

MZ>для него аспекты этой проблемы, я его к сож. не знаю.
да нет, там своих тараканов хватает. он окно делает как раз пропуская лишние строчки, в результате окно, близкое к началу выборки, летает, а если начинать с полумиллионной строчки — тормозит. MS SQL Server с хитрой конструкцией из ROW_NUMBER'ов летает и на таких количествах. файрберд тупил и на гораздо меньших цифрах, но там, возможно, я с индеками перемудрил.
Re[7]: определить позицию строки в запросе
От: MasterZiv СССР  
Дата: 31.08.09 11:18
Оценка:
ov wrote:

MS SQL Server с
> хитрой конструкцией из ROW_NUMBER'ов летает и на таких количествах.
> файрберд тупил и на гораздо меньших цифрах, но там, возможно, я с
> индеками перемудрил.


Это что за конструкция такая ?

Вообще, как вы узнаете ROW_NUMBER() строки априори, не выполняя запроса ?
Posted via RSDN NNTP Server 2.1 beta
Re[8]: определить позицию строки в запросе
От: ov  
Дата: 31.08.09 11:37
Оценка:
MZ>Это что за конструкция такая ?
что-то типа этого. сервера под рукой нет проверить точно:
SELECT * FROM (SELECT *,ROW_NUMBER() OVER (ORDER BY ...) AS ROW FROM ...)
WHERE ROW>=... AND ROW<...


MZ>Вообще, как вы узнаете ROW_NUMBER() строки априори, не выполняя запроса ?

запрос, конечно, выполняется. но внутри БД и я не задумываюсь как его наиболее оптимально выполнить с ее точки зрения.
Re[9]: определить позицию строки в запросе
От: niteshade123  
Дата: 01.09.09 09:33
Оценка:
Здравствуйте, ov, Вы писали:

ov>что-то типа этого. сервера под рукой нет проверить точно:

ov>
ov>SELECT * FROM (SELECT *,ROW_NUMBER() OVER (ORDER BY ...) AS ROW FROM ...)
ov>WHERE ROW>=... AND ROW<...
ov>


это аналитика
если был insert/update/delete между двумя выполнениями этого запроса, то номер строки — это средняя температура по больнице
Вам ясно сказали: по ID
про генераторы/сиквенсы для нумерации результатов упоминать не будем, т.к. за такое в любой софтостроительной конторе рвут руки, и это справедливо
Re[10]: определить позицию строки в запросе
От: ov  
Дата: 01.09.09 13:24
Оценка:
N>Вам ясно сказали: по ID
про ID речь шла в контексте поиска выделенной строки после применения новой сортировки.
а пример запроса с ROW_NUMBER этого всего лишь эмуляция окна в MS SQL сервере. возможно кривая, я не вникал подробно, т.к. Compact Edition ее не поддерживает.

поиск выделенной строки по ID после сортировки у меня прекрасно работает пока я считываю результат запроса полностью.
а я хочу читать блоками, чтобы не фетчить все 100К/500К записей разом.
а после смены сортировки неплохо бы еще и блок правильный найти с первого раза.
и тут, похоже, все очень запущено...

N>про генераторы/сиквенсы для нумерации результатов упоминать не будем, т.к. за такое в любой софтостроительной конторе рвут руки, и это справедливо

согласен.
Re[11]: определить позицию строки в запросе
От: MasterZiv СССР  
Дата: 01.09.09 14:19
Оценка:
ov пишет:

> поиск выделенной строки по ID после сортировки у меня прекрасно работает

> пока я считываю результат запроса полностью.
> а я хочу читать блоками, чтобы не фетчить все 100К/500К записей разом.
> а после смены сортировки неплохо бы еще и блок правильный найти с
> первого раза.
> и тут, похоже, все очень запущено...

Ещё раз -- вы хотите невозможного. Почти невозможного.

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

Фетчить большие наборы тоже плохо -- они никому не нужны, даже отсортированные.
Вам следует не заниматься поисками эфимерности, а улучшить
критерии выборки, чтобы сократить кол-во выбераемых с сервера
данных.
Posted via RSDN NNTP Server 2.1 beta
Re[12]: определить позицию строки в запросе
От: KRA Украина  
Дата: 01.09.09 14:38
Оценка: +1
Здравствуйте, MasterZiv, Вы писали:

MZ>Фетчить наборы данных можно только целиком. Вообще, если вы выбрали

MZ>набор, потом тот же запросы выполнили, и выбрали набор ещё раз --
MZ>это уже другой набор, к первому не имеющий никакого отношения.

Может я чего не понимаю, но чем плох вариант: сначала определяем на какую страницу попадает выбраная пользователем строка (по сути то с чего началась тема — нужно определить порядковый номер записи с даным идентификатором). Запрос получается вида (пишу с ораклиным синтаксисом)


select rn from  (
select e.*, rownum rn
from table e
order by
  e.field1, e.field2
) 
where id = :id


при наличии индексов по полям сортировки даже при 100к может работать с приемлимой скоростью на соответствующем железе (по крайней мере оракл с rownum-ами неплохо работает).

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

select e.* from (
select e.*, rownum rn
from table e
order by
  e.field1, e.field2
)
where rn between :start_index and :end_index


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

Естественно оба запроса в одной транзакции.

MZ>Фетчить большие наборы тоже плохо -- они никому не нужны, даже отсортированные.

MZ>Вам следует не заниматься поисками эфимерности, а улучшить
MZ>критерии выборки, чтобы сократить кол-во выбераемых с сервера
MZ>данных.

В теории согласен. Но вот на практике как это реализовать непонятно. Делать предварительную выборку количества без учёта сортировок и если в результате получается много — говорить пользователю, чтоб задал более жёсткие ограничения? Обычно пользователи хотят задавать любые критерии и иметь пейджинг.
Re[13]: определить позицию строки в запросе
От: ov  
Дата: 01.09.09 19:05
Оценка:
KRA>Может я чего не понимаю, но чем плох вариант:
вариант хорош. плохо то, что нет "настольной" БД, способной это сделать не подохнув...

KRA>Обычно пользователи хотят задавать любые критерии и иметь пейджинг.

угу. об этом и речь.
Re[13]: определить позицию строки в запросе
От: MasterZiv СССР  
Дата: 01.09.09 20:41
Оценка:
KRA пишет:

> Может я чего не понимаю, но чем плох вариант: сначала определяем на

> какую страницу попадает выбраная пользователем строка (по сути то с чего
> началась тема — нужно определить порядковый номер записи с даным
> идентификатором). Запрос получается вида (пишу с ораклиным синтаксисом)
>
>
> select rn from (
> select e.*, rownum rn
> from table e
> order by
> e.field1, e.field2
> )
> where id = :id
>
>
>
> при наличии индексов по полям сортировки даже при 100к может работать с
> приемлимой скоростью на соответствующем железе (по крайней мере оракл с
> rownum-ами неплохо работает).

Вот этот запрос:

select e.*, rownum rn
> from table e
> order by
> e.field1, e.field2
> )

который, между прочим, у вас всю таблицу обрабатывает,
должен сначала весь выбраться, отсортироваться,
и потом выбраться из него уже с id = :id.

Что тут может быть быстрого ?
Где тут поводы для оптимизации ? (кроме оптимизации ORDER BY
по индексу)

Кстати, по идее, order by в подзапросе СУБД может запросто
выкинуть, оно ни на что не влияет. Псевдоколонка rownum
же имеет смысл только в строке _возвращаемого_ набора данных,
она по идее там и должна генерироваться. Я не говорю, что
оракл так будет делать, просто логически тут всё очешь шатко.


> После этого, зная номер записи (и расчитав на какой странице она

> находится),

Как ?

мы можем подчитать только нужную нам страницу запросом вида
>
> select e.* from (
> select e.*, rownum rn
> from table e
> order by
> e.field1, e.field2
> )
> where rn between :start_index and :end_index
>
>
>
> Опять же в оракле такой запрос не приводит к тому, что читаются все
> данные целиком.

Ээээ.. доказательства будут ?

Оракл понимает, что такое rownum и как тут можно
> оптимизировать.

Как можно что-то оптимизировать по rownum, если он генерируется
в момент создания набора данных ?
Объясните, я не очень понимаю.

>

> Естественно оба запроса в одной транзакции.

> В теории согласен. Но вот на практике как это реализовать непонятно.

> Делать предварительную выборку количества без учёта сортировок и если в
> результате получается много — говорить пользователю, чтоб задал более
> жёсткие ограничения?

Да, например. Можно по любому запросу выводить, скажем, только первые 100
записей, и если есть ещё, писать, что часть данных были отброшены.

Больше 100-1000 записей никто читать не будет. Если это не выгрузка
данных куда-то для экспорта, или не отчёт какой-то для складирования, бесполезно
выводить более 100-1000 записей. Конкретные 100-1000 конечно варьируются в
зависимости от специфики приложения, но в общем идея такая.

Обычно пользователи хотят задавать любые критерии и
> иметь пейджинг.

Нахрена пейджинг нужен, если ты получаешь 10-100 нужных тебе записей ?
Posted via RSDN NNTP Server 2.1 beta
Re[13]: определить позицию строки в запросе
От: niteshade123  
Дата: 02.09.09 05:49
Оценка:
Здравствуйте, KRA, Вы писали:
KRA>

KRA>select rn from  (
KRA>select e.*, rownum rn
KRA>from table e
KRA>order by
KRA>  e.field1, e.field2
KRA>) 
KRA>where id = :id
KRA>

если так Вы хотите получить порядковый номер в сортировке e.field1, e.field2, то ошибаетесь

KRA>Опять же в оракле такой запрос не приводит к тому, что читаются все данные целиком. Оракл понимает, что такое rownum и как тут можно оптимизировать.

никакой магии
данные читаются целиком
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.