powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / IBPlus - неверно определяет количество записей
10 сообщений из 10, страница 1 из 1
IBPlus - неверно определяет количество записей
    #32157488
Даниил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуйте всем!
Есть такой код:
...
qTovar.Close;
qTovar.SQL.Clear;
qTovar.SQL.Add('SELECT AID, ANAIM, ALEVELS FROM GET_TOVAR_LIST(0,0)');
qTovar.Prepare;
qTovar.ExecQuery; //IB Expert возвращает 10 записей
if qTovar.RecordCount>0 then //В RecordCount только 1 (!) запись
...

Если у qTovar стоит AutoCommit ни одна запись не возвращается.

В чем здесь заковыка?
Заранее спасибо!

З.Ы. qTovar - IBPlus'овский query
...
Рейтинг: 0 / 0
IBPlus - неверно определяет количество записей
    #32162814
Даниил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Так никто и не подскажет? :(
...
Рейтинг: 0 / 0
IBPlus - неверно определяет количество записей
    #32162835
Фотография SmaLL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Для выполнения запросов типа SELECT надо использовать не ExecQuery , а Open
...
Рейтинг: 0 / 0
IBPlus - неверно определяет количество записей
    #32163624
Вообще-то, кроме Open надо будет еще сделать Last, чтобы в рекордкаунте содержалось действительное число выбранных записей
...
Рейтинг: 0 / 0
IBPlus - неверно определяет количество записей
    #32163686
Привет!

Типичная ошибка человека, переезжающго с БДЕ.

Код: plaintext
1.
2.
3.
4.
5.
qTovar.Close; 
qTovar.SQL.Clear; 
qTovar.SQL.Add('SELECT AID, ANAIM, ALEVELS FROM GET_TOVAR_LIST(0,0)'); 
qTovar.Prepare; 
qTovar.ExecQuery; //IB Expert возвращает  10  записей 
if qTovar.RecordCount> 0  then //В RecordCount только  1  (!) запись 


Постулаты:
1) В native библиотеках (IBX, FIBPlus и т.д.) необходимо явно управлять транзакциями
2) НЕ следует для подсчета числа записей использовать RecordCount


Теория:
Когда необходимо выполнить ЛЮБОЙ запрос, действия происходят в таком порядке:
1. Открывается транзакция
2. Текст запроса посылается на сервер и подготалвивается там - разбирается, строится карта использования индексов, формируется план запроса.
3. Параметры запроса посылаются на сервер
4. Запрос выполняется на сервере.
5. Клиентская библиотека начинает выбирать данные запроса с сервера на клиент в свой набор данных (dataset). Это называется fetch - фетч. Обычно для начала выбирается только одна запись.
6. Клиентская сторона выбирает в свой набор данных (dataset) столько записей, сколько ей нужно.
7. Транзакция закрывается согласно приказу клиентской библиотеки - обратите внимание, что это приказ может не совпадать с желаниями пользователя - см. ниже.
8. Если dataset не поддерживает кэширование, то после закрытия транзакции он закрывается.


Практика в БДЕ:

1) БДЕ скрывает механизм транзакций - поэтому происходит AutoCommit после запроса
2) БДЕ неявно использует не чистый "commit", а CommitRetaining - то есть транзакция подтверждается, но ее контекст не закрывается - и поэтому данные запроса после auticommit все равно видны.
3) БДЕ применяет (причем очень хорошо!) навигационный подход к возвращаемому набору данных, имитируя у него возможность движения вперед и назад (DataSet.Previous; DataSet.Next), а также более-менее корректно возвращаетчсило записей через RecordCount - для этого SQLLink-драйвер INTERBASE вынимает на клиента все записи.

Таким образом, БДЕ заточена на то, чтобы выбрать все рез-ты запроса на клиента и предоставить по нему очень быструю навигацию.

На нативных библиотеках ситуация другая:

1) Надо явно запускать транзакцию. Если стоит режим autocommit, то транзакция запустится сама, но в плане закрытия у нее ДРУГОЕ поведение - не как у БДЕ - см ниже.
2) До п.5 ситуация похожа и в БДЕ, и нативных библиотеках. Но после - сильные раличия. Во-первых, нативные библиотеки НЕ ЗАТОЧЕНЫ под выемку большого кол-ва данных - они берут только первую запись и ждут. Вызов DataSet.RecordCount всегда возвращает только текущее количество записей в датасете - а оно сразу после открытия действительно равно 1.
3) Нативные библиотеки рассчитаны на сервер-ориентированный подход и не слишком хорошо поддерживают работу с большими наборами данных - во всяком случае, хуже БДЕ. Сама идеология сервер-ориентированного подхода отрицает необходимость выемки на клиента многих (100-10000-...) записей. Ведь эти записи в любом случае не поместятся на экране и физиологически не смогут быть пронализированы пользователем! А если пользователь захочет еще порцию - надо перевыполнить запрос с новыми границами или условиями.
4) Нативные библиотеки используют Commit, а не CommitRetaining, поэтому при закрытии транзакции (например, в режиме AutoCommit) DataSet закрывается! Чтобы избежать этого, транзакцию надо либо явно закрывать ПОСЛЕ проведения всех операций над полученными данными, либо использовать механизмы Cashed Updates.

Выводы:
При использовании native библиотек доступа подсчитывать число записей в результате запроса и двигаться по результатам запроса нецелесообразно - лучше использовать отдельный запрос с SELECT Count(*)... и уточнение условий запроса.

C уважением
Алексей Ковязин
...
Рейтинг: 0 / 0
IBPlus - неверно определяет количество записей
    #32163973
Даниил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Огромное спасибо Алексею Ковязину за столь исчерпывающий ответ. Я действительно только-только переезжаю с BDE и еще не во все "въехал" :)
У меня включено кэширование, AutoCommit, ... в общем все по максимуму - Auto... Не все-таки придется немного ручками поправить.

>Сама идеология сервер-ориентированного подхода отрицает необходимость
>выемки на клиента многих (100-10000-...) записей. Ведь эти записи в любом
>случае не поместятся на экране и физиологически не смогут быть
>пронализированы пользователем! А если пользователь захочет еще порцию -
>надо перевыполнить запрос с новыми границами или условиями.

Вопрос такой возник:
У пользователя на экране в табличке показан прайс (примерно 40000 наименований). Пользователю надо из этой таблички что-нибудь выбирать (т.е. курсором, потом Enter нажать и т.п.). Как в таком случае запрашивать с сервера НЕ ВСЕ ЗАПИСИ ИЗ ЭТОЙ ТАБЛИЧКИ, а только те, которые нужно на экране показать???

Спасибо
...
Рейтинг: 0 / 0
IBPlus - неверно определяет количество записей
    #32164867
Привет!

Код: plaintext
1.
2.
3.
4.
5.
Вопрос такой возник: 
У пользователя на экране в табличке показан прайс 
(примерно  40000  наименований). Пользователю надо из этой таблички что-нибудь выбирать (т.е. курсором, 
потом Enter нажать и т.п.). 
Как в таком случае запрашивать с сервера НЕ ВСЕ ЗАПИСИ ИЗ
 ЭТОЙ ТАБЛИЧКИ, а только те, которые нужно на экране показать??? 


Вот именно про такой случай я и писал. Если загружать все 4000 на клиента путем DataSet.Open, DataSet.Last, то BDE будет вне конкуренции - очень быстро.

А для native библиотек подход примерно такой.
- Пользователь 4000 записей сразу просмотреть не может, так?
- Поэтому надо выводить меньше записей.
- Чтобы выводить меньше записей, надо уточнить условия.

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

Уточнение предментых условий.
Этот вариант является истинно SQL-евским, но пользователи, привыкшие к огромным листам EXCel, его плохо переносят (но переучивание возможно :).
Когда пользователь ищет какой-то товар, надо попросить его сначала ввести первые буквы наименования, категорию товара, или ограничение по цене или еще что-то в этом роде, и потом выполнить запрос вида:

Код: plaintext
1.
2.
Select *
from table t
where t.product_name starting with 'Motoro' And t.price< 100 


при этом выйдет гораздо меньшее число записей.

Псевдоуточнение
Это вебовский прием, который можно увидеть на любом сайте, где производится поиск.
Мы создаем запрос как нам будет угодно (в том числе можно использовать и первый способ, с предметными условиями), и затем добавляем туда следующую вещь:
1) Либо конструкцию SELECT FIRST <x> SKIP <y> .... для вывода первых x записей после пропуска y. (Это в Firebird, в IB конструкция выглядит как ROWS x TO y в самом конце запроса)
2) Либо, если у нас нет никакой сортировки при выборе, то можно воспользоваться первичным ключом и добавить в WHERE такое условие:

Код: plaintext
1.
2.
3.
4.
Select * from table t
where .....
and (
t.первичный_ключ >=y and t.первичный_ключ <=x+y
)


В том и другом случае мы получим ограниченный набор записей в 100 штук (ну или сколько душа пожелает).

Разумеется, эти x и y должны быть параметрами в запросе.
Далее, у пользователя появляется две кнопки Страница вперед и Страница назад , после нажатия на которые параметры запроса увеличиваются/уменьшаются на заданный шаг.
Также можно выполнить еще запрос с Count(), посчитать общее количество записей и вывести их для справки.

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


Недостатки способа:
1) Нельзя воспользоваться multi-select в grid. Это так, поэтому выбор товаров придется сдеать в стиле "корзины", когда кнопка Добавить переносит выбранный товар в другой ДатаСет.

2) Пользователь может захотеть "гладкий скроллинг", без всяких кнопок. В сущности, можно сделать отслеживание положения курсора в гриде и вызывать нужный запрос при приближении к концу, но не стоит - лучше убедить пользователя в целесообразности поэтапного вывода. Кроме того - см. достоинство N.3

3) Больше кодирования. Да, хорошо было в БДЕ - бросил грид, написал Table.open и все заработало... Но надо четко понять, что таким способом написать приложение для большого массива данных нельзя. По воробьям и слонам стреляют из разных ружей.


Достоинства:

1) Очень быстрая работа и малая нагрузка сервера. Если есть все нужные индексы, то запрос на выборку выполняется моментом, а сервер при этом почти не загружен.
2) Масштабируемость. Такой подход будет работать и на 4000 записей, и на 4000000. Разница будет незаметна.
3) Легкий переход на веб-решение. Если вдруг начальство захочет выводить прайс лист на веб-сайте с возможностью поиска, то те же самые запросы и механизмы можно будет легко прикрутить к веб-решению.
4) Все правильные пацаны делают так )))

С уважением,
Алексей.
...
Рейтинг: 0 / 0
IBPlus - неверно определяет количество записей
    #32165676
Даниил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Привет Алексей!
Спасибо за подробности.
Пойду убеждать пользователя, что весь прайс на экране ему ни к чему :)
...
Рейтинг: 0 / 0
IBPlus - неверно определяет количество записей
    #32165679
alex_k
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Ковязин
Спасибо, листание - вот чего оказывается нехватало моим программам :-)
...
Рейтинг: 0 / 0
IBPlus - неверно определяет количество записей
    #32166421
Код: plaintext
1.
 2  Ковязин 
Спасибо, листание - вот чего оказывается нехватало моим программам :-)


Просто ты, наверное, не писал книжный каталог на 300000 библиографических карточек :)

WBR,
Alexey
...
Рейтинг: 0 / 0
10 сообщений из 10, страница 1 из 1
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / IBPlus - неверно определяет количество записей
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]