-
Кто опытен, помогите пожалуйста разобраться в таком обстоятельстве:
DBGridEh прицепленный к DataSet (от FIBPlus), отображает примерно 92тыс.записей В таблице 3 поля: ID (целое), FLAG (char[1]) и NUM (целое) И вот - нужно сделать апдейт числового поля группы записей, размещённых между теми записями, у которых FLAG - не пуст. У каждой очередной группе записей, размещённых между записями с непустым флагом: нужно изменить поле NUM (просто в это поле записывается следующий по порядку номер - и всё).
Так вот интересный эффект, Если эту задачу решать, просматривая в цикле сам DataSet:
iCounter := 1; iPrevRec := 1; DS.First; while not DS.Eof do begin if DS.FieldByName('FLAG').AsString <> '' then Inc(iCounter); DS.Edit; DS.FieldByName('NUM').AsInteger := iCounter; DS.Post; DS.Next; end; DS.FullRefresh;
- то после этой операции - в прицепленном к Dataset гриде записи нормально скроллируются, как и до апдейта, но - пройти "пешком" 92тыс. записей - долго...
Тогда я переписал код, используя SQL запросы:
iCounter := 1; iPrevRec := 1; QueryFetch.SQL.Text := 'SELECT ID FROM TAB WHERE FLAG <> ''''' QueryFetch.ExecQuery; // - мы сразу на 1 записи... QueryFetch.Next; while not QueryFetch.Eof do begin // скачем по записям с флагом QueryUpdate.SQL.Text := 'UPDATE TAB SET NUM = ' + IntToStr(iCounter) + 'WHERE ID >=' + IntToStr(iPrevRec) + ' AND ID < ' + QueryFetch.Fields[0].AsString; QueryUpdateVerses.ExecQuery; // апдейт поля NUM у группы записей Inc(iCounter); // увеличили счётчик iPrevRec := QueryFetch.Fields[0].AsInteger; // запомнили ID для использ. в след. итерации QueryFetch.Next; end; // после цикла - апдейт последней группы, но это не важно...
Так вот - теперь собственно сам казус - почему-то после этого варианта кода - грид, отображающий эту таблицу стал просто жутко тормозить!! Я ради интереса провёл один эксперимент: попробовал делать апдейт с помощью SQL запросов не всех записей таблицы, а только части, оказалось, чем меньше записей обновлялось, тем меньше потом тормоза!..
Может кто-нибудь подсказать - что это за "глюк" такой?
-
> QueryUpdateVerses.ExecQuery; // апдейт поля NUM у группы > записей
здесь я ошибся, должно быть:
QueryUpdate.ExecQuery; // апдейт поля NUM у группы записей
-
Это в продолжение твоей темы о прогрессиндикаторе?
Выбрать с непустым флагом и пронумеровать? - Один запрос на обновление с этим условием + генератор, и желательно индекс по полю с флагом, и никаких циклов не надо. Но что-то это странное, я ещё согласен, когда один раз/иногда по каким-то причинам надо такое, но постоянно.
-
> Может кто-нибудь подсказать - что это за "глюк" такой?
Это не глюк, это дурная голова. DataSet.DisableControls;
try
DataSet.Firest;
while not DataSet.Eof do
try
......
finally
DataSet.Next;
end;
finally
DataSet.EnableControls;
end;
-
Спасибо за участие, да - это в продолжение вопроса о прогрессбаре, с ним разобрался, и вот - двигаюсь дальше..
> Один запрос на обновление с этим условием + генератор
Вы меня не поняли. Записи в таблице выглядят примерно так: ID FLAG NUM 1 > 0 2 0 3 0 4 > 0 5 > 0 6 0 7 > 0 А после апдейта поля NUM должно быть так: ID FLAG NUM 1 > 1 2 1 3 1 4 > 2 5 > 3 6 3 7 > 4 Поэтому то что Вы предлагаете с генератором - сюда вроде не подходит.
> когда один раз/иногда по каким-то причинам надо такое, но > постоянно.
- а вот эту фразу я вообще не понял, поясните, что вы имели ввиду.
...Мне в принципе интересно, почему начало тормозить перемещение по Dataset, если в SQL запросах на апдейт я вроде не накосячил.
Извините, если мои вопросы "не на уровне", я новичёк...
-
> [3] Ega23 © (30.12.10 02:07) > Это не глюк, это дурная голова. > DataSet.DisableControls;
А я понял, автор бегает по одному набору, а смотрит в гриде в другом.
-
> DataSet.DisableControls;
Вы имеете ввиду, что я в коде забыл запретить перерисовку Control-ов, связанных с DataSet?..
У меня используется DisableControls, просто я упростил пример, и не внёс туда эти строки, потому что и так понятно, что лучше не скроллировать DataSet без такого приёма...
-
> А я понял, автор бегает по одному набору, а смотрит в гриде > в другом.
Это шутка?..
-
> [4] Anthony © (30.12.10 02:10) > > когда один раз/иногда по каким-то причинам надо такое, но > > постоянно. > > - а вот эту фразу я вообще не понял, поясните, что вы имели ввиду.
Что за задача, что надо перелопачивать и перенумеровывать постоянно, судя по теме с прогрессбаро. Т.е. не косяк ли в архитектуре.
С запросом, может и такое можно сделать, если подумать.
-
> [7] Anthony © (30.12.10 02:21) > > А я понял, автор бегает по одному набору, а смотрит в гриде в другом. > > Это шутка?..
Нет. Я так понял из
> [0] Anthony © (30.12.10 00:38) > Если эту задачу решать, просматривая в цикле сам DataSet: > DS.First; ... > Тогда я переписал код, используя SQL запросы: > > QueryFetch.SQL.Text := 'SELECT ID FROM TAB WHERE FLAG <> > QueryUpdate.SQL.Text := 'UPDATE TAB SET NUM = ' + IntToStr(iCounter)
-
> Что за задача, что надо перелопачивать
Да простая вобщем то задача. Я просто не упомянул, чтобы не усложнять, что в каждой записи ещё присутствует текстовое поле, довольно объёмное, и вся ценность - именно в нём. Все текстовые поля имеют одну характерную особенность, по которой их нужно разбить на соотв.группы. Пользователь, просматривая всю таблицу (в гриде) - помечает записи, являющиеся началами этих групп, а после окончания пометки - записи в группах должны пронумероваться... Вот и всё. Нормальная задача.
> С запросом, может и такое можно сделать, если подумать.
Так я его и привёл уже в примере! Один запрос - скачет по записям с ненулевым флагом - а другой - апдейтит записи между ними. Разве Вы сможете предложить что-то проще?..
-
> А я понял, автор бегает по одному набору, а смотрит в гриде > в другом.
Нет-нет. Если Вы не пошутили, конечно же речь идёт об одном и том же DataSet. Я просто никак не пойму, почему в первом случае кода - после окончания апдейта - всё в порядке, а во-втором - начинаются жуткие тормоза!..
-
> а во-втором - начинаются жуткие тормоза!.. while not QueryFetch.Eof do begin QueryUpdate.SQL.Text := 'UPDATE TAB SET NUM = ' + IntToStr(iCounter) + 'WHERE ID >=' + IntToStr(iPrevRec) + ' AND ID < ' + QueryFetch.Fields[0].AsString; //про параметры тебе уже говорили. опять не "обратил внимания"?
QueryUpdateVerses.ExecQuery; //??? пере запрос чего? говорил вроде что туже самую таблицу правишь... а тут + Verses, т.е. запрос меняется у одного выполняется другой?
Inc(iCounter); // увеличили счётчик iPrevRec := QueryFetch.Fields[0].AsInteger; // запомнили ID для использ. в след. итерации QueryFetch.Next; end
это карма, тут запросы тут совершенно лишние, сначала делать изменение запросом в базе после пере запрос... вариант с кешированными изменениями лучше... сначала все исправили в рекордсете на клиенте, после "сбросили" это в базу, и никаких лишних "телодвижений".
-
>Anthony © (30.12.10 02:35) [11] Вы кстати уверены что пользователь в состоянии просмотреть все 92 тысячи записей? И как ваша программа должна действовать в случае, если НД будет банально отсортирован? Я так понял, что пользователь, просматривая записи "отмечает" "пограничные" записи а не сразу всю группу?
-
> Anthony (30.12.2010 02:16:06) [6]
Где там у тебя никого не интересует, здесь оперируем только приведеным кодом.
-
> Anthony (30.12.2010 02:21:07) [7]
Это не шутка, а как не смешно частая ошибка.
-
Я может чего не понял после шампанского и фуршета, но разве нельзя одним запросом все сделать? UPDATE TAB SET NUM = NUM+1 WHERE FLAG<>''
ЗЫ: 92 тыс записей со стуктурой ID (целое), FLAG (char[1]) и NUM (целое) в гриде - это жесть! 8-)
-
ID FLAG NUM 1 > 0 2 0 3 0 4 > 0 5 > 0 6 0 7 > 0 А после апдейта поля NUM должно быть так: ID FLAG NUM 1 > 1 2 1 3 1 4 > 2 5 > 3 6 3 7 > 4
Napisi eta procedur adocommand.commantext i palucish resultat
declare @i int
set @i=0
update tab set @i=Num=@i+1 where flag<>''
set @i=0
update tab set @i=Num=@i+1 where flag=''
-
куча мелких запросов - много медленнее, чем ОДИН "большой запрос
-
> adigozelov ©
MS SQL тут не причем
-
> UPDATE TAB SET NUM = NUM+1 WHERE FLAG<>''
Это Вам после шампанского пришло в голову или после фуршета? ))) Сами проанализируйте - что делает Ваш запрос...
> вариант с кешированными изменениями лучше...
- можно более понятным языком, очём идёт речь?
> куча мелких запросов - много медленнее, чем ОДИН "большой > запрос
- а Вы сначала попробуйте написать это одним запросом!..
> QueryUpdateVerses.ExecQuery; //??? пере запрос чего? говорил > вроде что туже самую таблицу правишь... а тут + Verses
- посмотрите [1] - я допустил в примере кода ошибку и сразу поправился, Вы наверно просто не обратили внимание...
> Я так понял, что пользователь, просматривая записи "отмечает" > "пограничные" записи а не сразу всю группу?
- да, правильно Вы поняли. Пользователь просматривает текстовое поле у всех 92000 записей, делая пометки, из которых потом получаются группы. Автоматизировать эту операцию нельзя, потому что признаки новой группы в тексте специфичны и понятны только человеку...
> Где там у тебя никого не интересует, здесь оперируем только приведеным кодом.
- это Вы про Disable.Controls ? Может я не сумел донести вопрос... Зависания прокрутки грида - а точнее - это тормоза самого DataSeta у меня начинаются НЕ во время SQL запросов, а ПОСЛЕ всего апдейта, поэтому я и не написал этих строк в коде, они - вообще никакого отношения НЕ имеют к моему вопросу, только зря насчёт них "копья ломали", а сама суть вопроса осталась никем не затронутой.
> //про параметры тебе уже говорили. опять не "обратил внимания"?
- в какой подсказке говорилось про "параметры"? Простите - не увидел, поясните пожалуйста, что имеете ввиду...
-
> они - вообще никакого отношения НЕ имеют к моему вопросу, > только зря насчёт них "копья ломали", а сама суть вопроса > осталась никем не затронутой.
Позволь нам судить имеют или нет.
-
> - можно более понятным языком, очём идёт речь? могу только на примере ADO, "твоих" фибов не знаю. но вообще кеш он и в Африке кеш... смысл один, работаешь с данными в одном месте (на клиенте) после скидываешь результат в другое (сервер). а не так как ты пытаешься (и ради чего? просто впихнуть запросы т.к. круто? или чего? они у тебя как самоцель) промежуточные результаты сохраняешь на сервер, а для показа на клиенте делаешь после пере запрос только что отправленных данных. > а сама суть вопроса осталась никем не затронутой. если бы ты знал в чем суть, вопроса бы не было. поэтому всегда ПОКАЗЫВАЙ ВСЕ КАК ЕСТЬ, БЕЗ ДЕЛЕНИЙ НА "ЭТО ПОКАЖУ, А ЭТО К ВОПРОСУ НЕ ОТНОСИТСЯ". чтобы решать, что относится, а что нет нужно знать ответ. > - в какой подсказке говорилось про "параметры"? http://pda.delphimaster.net/?n=18&id=1293575440Inovet © (29.12.10 18:07) [10]> А какие ещё "параметры надо"? > Разве такой код можно написать, чтобы он работал быстрее? вот этот можно.
-
> если бы ты знал в чем суть, вопроса бы не было.
- не согласен. Если бы я знал суть ПРОБЛЕМЫ а не вопроса, тогда да, вопроса бы не было. А я сказал - что подсказывающие не поняли СУТЬ ВОПРОСА.
> ПОКАЗЫВАЙ ВСЕ КАК ЕСТЬ, БЕЗ ДЕЛЕНИЙ НА "ЭТО ПОКАЖУ, А ЭТО > К ВОПРОСУ НЕ ОТНОСИТСЯ".
- глюк имеет место быть именно в том коде, что я привёл.
> > Разве такой код можно написать, чтобы он работал быстрее? > вот этот можно.
- а это вообще про что? У меня вопрос про тормознутость DataSet, после того как по нему прошлись апдейт-запросами, а не про скорость работы...
И ещё: мастера Delhi - вы перевели мой вопрос в категорию "Начинающим" - почему?.. Никто даже близко не ответил, почему у DataSet могли бы начаться тормоза... Вы думаете - если Вы как "спецы" не смогли разобраться что к чему - "Начинающие" помогут?
-
> Если бы я знал суть ПРОБЛЕМЫ а не вопроса, тогда да, вопроса > бы не было http://www.gunsmoker.ru/2008/10/x-y-z.html > И ещё: мастера Delhi - вы перевели мой вопрос в категорию > "Начинающим" - почему?
Только модератор может перенести вопрос в другую конференцию. И не надо его спрашивать "почему".
-
> http://www.gunsmoker.ru/2008/10/x-y-z.html
Забавно, но не мудро. Человеку как-раз и нужно отвечать на его уровне понимания, а не со своих "высот", кои ещё и весьма сомнительны, поскольку думаю согласитесь, что вполне может быть случай, когда задающий на форуме вопрос по уровню может дать фору многим, вот так свысока бросающим обрывки малопонятых фраз в ответ на спрошенное...
-
> Забавно, но не мудро. Человеку как-раз и нужно отвечать > на его уровне понимания, а не со своих "высот"
Ну это ищи в "социальных сетях". А не на профессиональном форуме.
> когда задающий на форуме вопрос по уровню может дать фору > многим
И пальцы "растопыривай" тоже там. Мы пока не увидели "форы". Равно как и "уровня". Или найми специалиста, если есть возможность ему заплатить.
-
> Никто даже близко не ответил, почему у DataSet могли бы начаться тормоза... вот это вот позиция начинающего... "спец" ищет проблему у себя в коде в первую очередь (ну, скоре просто не допустит подобного, т.к. не делает странного), а начинающий в датасетах, виндовс, и т.д., только не у себя... т.е. один делает программу на том что есть, под систему, другой пишет абы как и ожидает, что система поймет.
для того чтобы ответить нужна инфа... но если хочешь, ну чтобы просто близко... может твои фибы поддерживают серверный курсор и начинают обновлять "в фоне" т.к. записи на сервере изменились, вот тебе и "тормоза".
> Человеку как-раз и нужно отвечать на его уровне понимания а разве тебе не сказали что делать, правильные подходы? и где попытки выполнить, проверка результатов на том, что посоветовано?
-
1. Я вот сильно сомневаюсь, что пользователь в состоянии просмотреть глазками и принять решения касательно 92000 записей одновременно. Банально посчитав что на принятие решения ему нужна 1 сек. ему понадобиться больше суток что бы их тупо просмотреть. 2. Всегда нужно использовать параметры в запросах. Оно конечно к делу не относится, но может здорово нагадить Строка типа QueryUpdate.SQL.Text := 'UPDATE TAB SET NUM = ' + IntToStr(iCounter) + 'WHERE ID >=' + IntToStr(iPrevRec) + ' AND ID < ' + QueryFetch.Fields[0].AsString;
очень неправильна по своей сути. Функция IntToStr(iPrevRec) - при разных региональных настройках может вернуть разный разделитель целого и дробного - и ваша программа просто перестанет выполняться. Если вы таким способом будете передавать например дату, то вообще будет "весело". 3. Вообще из примера мне не ясно как оно работает. QueryFetch.SQL.Text := 'SELECT ID FROM TAB WHERE FLAG <> '''''
QueryFetch.ExecQuery;
Почему Вы решили, что этот запрос вам вернет НД в таком, же порядке, как его просматривал пользователь? В вашем "зависающем" примере мне не ясно, какой датасет отображается в DBGridEh? В первом примере это, я так понимаю DS. 4. Вам предложили выше по ветке массу вариантов: От применения одного запроса, до отключения контролов, дабы не мешали. Вы что нибудь из этого попробовали? 5. В вашей теме уже 27 ответов, а вы по какой то причине обвиняете тех, кто пытается вам помочь, в том, что они за вас не хотят все сделать. Это нехорошо.
-
> > куча мелких запросов - много медленнее, чем ОДИН "большой > > > запрос > > - а Вы сначала попробуйте написать это одним запросом!.. >
> Anthony © (31.12.10 00:04) [20]
execute block тебе в помощь !
-
ОГРОМНОЕ СПАСИБО ВСЕМ, особенно благодарю Max Zyuzin за конкретность...
У меня есть новости по поводу моего вопроса, кому интересно, делюсь: "Тормоза" прокрутки DataSet пропали только после того, как уже после окончания апдейт запросов - я переоткрыл саму базу! Почему так происходит - не знаю, может быть это особенности или библиотеки FIBPlus или самого Firebird.
Однако, есть факи: Если делать изменения в каждой записи таблицы, крутя в цикле сам DataSet, - то после изменений (во всех 92000 записях) - "тормозов" нет. Если же делать апдейт записей SQL запросами, (естественно при этом заблокировав компоненты просмотра DataSet.DisableControls) - то после окончания операции - DataSet жутко тормозит.
Пробовал вообще отключать DataSet от базы на время прохождения запросов - не помогает... Потом вот уже тупо в конце кода поставил: Database.Close; Database.Open; - после чего скроллинг пошел снова без тормозов.
Не знаю, наверно причина где-то глубоко и в силу малого опыта я в этом механизме не разберусь, поэтому буду использовать просто изменения записей Dataseta в цикле, и всё... Тем более, оказалось, что этот метод оказался по скорости НЕ МЕДЛЕННЕЕ, чем SQL апдейты! (У меня - НЕ СЕРВЕРНЫЙ вариант приложения!) Возможно конечно, что эту операцию можно как-то быстро сделать одним запросом, но сам я не знаю как, и пока никто такого кода тоже сюда не привёл. (Это - тоже факт!..)
> execute block тебе в помощь !
Я не знаю, что такое "execute block", если можно - поясните
> ему понадобиться больше суток что бы их тупо просмотреть.
- да, так и есть, эту таблицу записей пользователь помечал примерно 2 недели
> Функция IntToStr(iPrevRec) - при разных региональных настройках > может вернуть разный разделитель целого и дробного
- не понял... Разве целое число iPrevRec - имеет дробную часть? И вообще, если в уже откомпилированном (EXE) коде IntToStr вернула всё правильно, то у заказчика она вернёт по-другому? Думаю, так не может быть
> Почему Вы решили, что этот запрос вам вернет НД в таком, > же порядке, как его просматривал пользователь?
Все запросы отсортированы по полю ID. А вообще - это замечание - тоже не касается сути моего вопроса... Ну и что - если мой запрос на апдейт - был (бы) составлен неверно, и записал в поле NUM не то, что надо, суть вопроса то не в этом!! Если бы я запросом - просто обнулил поле NUM у всех записей, потом - всё равно начинаются "тормоза", я проверял
> Всегда нужно использовать параметры в запросах
-пробовал переписать запрос, используя параметры - один и тот же результат...
> 3. Вообще из примера мне не ясно как оно работает. > QueryFetch.SQL.Text := 'SELECT ID FROM TAB WHERE FLAG <> ''''' > QueryFetch.ExecQuery; // - мы сразу на 1 записи...
- работает очень просто: после выполнения запроса - в QueryFetch оказываются все записи с ненулевым полем FLAG, и + к этому (по умолчанию) - мы сразу "стоим" на первой записи этого запроса. А потом - начинаем фетчить в цикле его записи, и всё.
-
> [30] Anthony © (31.12.10 15:18) > и пока никто такого кода тоже сюда не привёл. (Это - тоже факт!..)
Так код что ли надо давать?
> [30] Anthony © (31.12.10 15:18) > > execute block тебе в помощь ! > > Я не знаю, что такое "execute block", если можно - поясните
Так прочитать может в справке надо? Так же как и о хранимых процедурах.
> [30] Anthony © (31.12.10 15:18) > Все запросы отсортированы по полю ID.
Это разве было где-то показано?
> [30] Anthony © (31.12.10 15:18) > мы сразу "стоим" на первой записи этого запроса
Этого да. Но о сортировке не было сказано, вот и вывод - не известно где стоим. Сортировка по сурогатному ID тоже не понятна, ну да ладно.
> [30] Anthony © (31.12.10 15:18) > И вообще, если в уже откомпилированном (EXE) коде IntToStr > вернула всё правильно, то у заказчика она вернёт по-другому? > Думаю, так не может быть
Зря так думаешь - это надо осознанно сделать. Да и зачем так, если можно правильно
> [30] Anthony © (31.12.10 15:18) > > Всегда нужно использовать параметры в запросах > > -пробовал переписать запрос, используя параметры - один > и тот же результат...
Вот и надо оставить с параметрами. А лучше см. выше.
> [30] Anthony © (31.12.10 15:18) > У меня - НЕ СЕРВЕРНЫЙ вариант приложения!
Ну и что, писать надо правильно.
По существу вопроса. Надо же проверять это. А не окажется ли здесь та проблема с расширением gdb в Windows.
-
> Надо же проверять это. А не окажется ли здесь та проблема > с расширением gdb в Windows.
- а что это: "проблема с gdb" ? - и как Вы предлагаете "это" проверить?
-
> [32] Anthony © (31.12.10 16:27) > - а что это: "проблема с gdb" ? > - и как Вы предлагаете "это" проверить?
Это разное. Проверять всё кому-то у себя. А о gdb, переименовать его в другое - fb, например.
-
> А о gdb, переименовать его в другое - fb, например.
- думаете это может помочь? интересно... А какой именно файл (или файлы) с таким разрешением Вы предлагаете переименовать?
-
> [34] Anthony © (31.12.10 17:13) > А какой именно файл (или файлы) с таким разрешением Вы предлагаете > переименовать?
Если незнакомо, то, видимо, никакой, а иначе файл БД.
-
> Anthony © (31.12.10 17:13) [34] > > > > А о gdb, переименовать его в другое - fb, например. > > - думаете это может помочь? интересно... > А какой именно файл (или файлы) с таким разрешением Вы предлагаете > переименовать?
Должно помочь. Читать здесь: http://www.ibase.ru/ibfaq.htm#xp
-
Для FireBird менять расширение с gdb на fdb.
-
> > А какой именно файл (или файлы) с таким разрешением Вы > предлагаете > переименовать? > Если незнакомо, то, видимо, никакой, а иначе файл БД.
Файлы БД Firebird изначально имеют расширение .FDB Поэтому переименовывать нечего
-
|