Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft Access Новый топик    Ответить
 "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
Varan
Member

Откуда:
Сообщений: 1258
Неоднократно встречал такие фразы (употребляются обычно с негативным оттенком) как "метод курсорных переборов записей", "БД на курсорах" и т.п., но никак не могу понять, что это такое. Хорошо бы было, чтобы кто-нибудь разъяснил, что это такое, желательно с примерами, и рассказал бы, в чем вред этих методов и как от них избавиться. А то вдруг я этим болен, и не знаю об этом?
15 дек 03, 20:25    [460475]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
Lepsik
Member

Откуда: glubinka
Сообщений: 4256
это когда вместо того написать

SELECT COUNT(*) FROM my_table

и получить результат через 0.00001 сек.

пишут цикл и перебирают часами все записи, пытаясь подсчитать их количество.
15 дек 03, 22:53    [460549]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
Varan
Member

Откуда:
Сообщений: 1258
А откуда такое словосочетание взялось и что, собственно, означает "курсор" в данном контексте?
16 дек 03, 11:15    [460965]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
Pavel Krupets
Member

Откуда:
Сообщений: 105
Курсор использется для просмотра таблицы по строкам, как связь между реляционной моделью данных и моделью языков программирования. Так как при работе с курсором база должна хранить дополнительную информацию и обработка происходит не за один сеанс связи а за N то естественно скорость будет ниже.
16 дек 03, 11:28    [461002]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
CtrlAlt
Member

Откуда:
Сообщений: 437
Курсор, грубо говоря, это указатель на текущую запись. Когда используешь recordset, то имеешь доступ только к одной строке. Но перемещая курсор, можно последовательно получить доступ ко всей таблице. Наглядно представить это можно посмотрев на форму в обычном виде (Single Form).

Ничего плохого в курсорах нет, просто применение их там где можно без них обойтись неразумно. Смотри пример Lepsik. Цикл по записям имеется в виду с помощью recordset'a
16 дек 03, 11:33    [461016]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
Serafim
Member

Откуда: Riga
Сообщений: 208
А откуда такое словосочетание взялось и что, собственно, означает "курсор" в данном контексте?

то идет от терминологии SQL сервера, когда для перебора записей вы открываете курсор - так вот оно там называется - вот примерчик - перебираем список таблиц - отнимаем все права, потом даем право на просмотр (для группы)

DECLARE @tbl varchar(50)

DECLARE tabCursor CURSOR
for SELECT name from sysobjects where xtype='U'
OPEN tabCursor
FETCH NEXT FROM tabCursor INTO @tbl
WHILE (@@FETCH_STATUS <> -1)
BEGIN
exec('REVOKE ALL ON ' + @tbl +' TO '+ @gr)
exec('GRANT SELECT ON ' + @tbl +' TO '+ @gr)
FETCH NEXT FROM tabCursor INTO @tbl
END
DEALLOCATE tabCursor
16 дек 03, 11:34    [461020]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
Varan
Member

Откуда:
Сообщений: 1258
Понял в общих чертах. Из этого следует, что я сам этой болезнью страдаю. Чтобы наметить пути избавления, приведу пример задачи, вдруг кто подскажет, как это сделать без курсоров?
Есть таблица ТБЛ1(Поле1(PK), поле2, Поле3...) с данными, причем каждое значения каждого поля может содержать некорректности (в том смысле, что их содержимое не соотвтствует "Формату", заданному для каждого поля. Под "форматом" понимается либо определенное чило символов для строковых полей, либо определенный "вид" строки, например для определенных полей значение должно содержать определенную подстроку и т.п.
Задача состоит в том, чтобы перенести в ТБЛ2 (структура та же) данные, соответствующие формату (прошедшие проверку). Строки, хотя бы одно значение любого поля которой не прошло проверку, должны быть помещены в ТБЛ3 (структура та же). В таблицу ТБЛ4(Поле1(FK),ИмяПоля, Сообщение_об_ ошибке) должны прописыватья сообщения о несоответствии формату, например, если в 10 строке входных данных в Поле5 данные не соответствуют формату, в строке ТБЛ4 должно быть:
10;Поле5;Ошибка:Должно быть 4 символа, а их 5
16 дек 03, 11:54    [461077]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
incold
Member

Откуда:
Сообщений: 1580
2 Varan
В данной задаче все будет зависет от того, какое соотношение кол-ва строк в таблице и кол-ва всех проверок по всем полям.

Если кол-во проверок по всем полям больше чем кол-во строк в таблице, то более оптимальным вариантом будет как раз курсор.

Если же кол-во строк в таблице на порядки превышает кол-во всех проверок, то более оптимальным будет примерно след. вариант (для T-SQL):
- на каждую проверку выполняется
if exists("запрос с условием не несоответствие заданным параметрам")
если записи есть, тогда

insert into tab4(...)
select ... from tab1 where ("такое же условие как в запросе выше")
- после всех проверок выполняется запрос
insert into tab2(...)
select ... from tab1
where ("перечисление всех условий")
16 дек 03, 12:10    [461119]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
Varan
Member

Откуда:
Сообщений: 1258
incold,
"Если кол-во проверок по всем полям больше чем кол-во строк в таблице"
- немного не понял, как может быть число проверок меньше числа строк? Например, в таблице 15 полей, 10 из них надо проверить если 1000 строк, то имеем 10000 проверок, т.е. число проверок = число строк*число проверяемых полей, что всегда больше числа строк при числе проверяемых полей>1
16 дек 03, 12:25    [461163]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
incold
Member

Откуда:
Сообщений: 1580
Вот это и есть курсорная болезнь

Число проверок всех полей, но проверяются они сразу по всем записям одним запросом.
Если число полей 15, проверить нужно 10 полей.
Выполняем 10 запросов на проверку каждого поля во всех записях.
Т.е. число всех проверок равно 10.

Другой вариант:
число полей 15, нужно проверить 10 полей по 10 критериям - итого 100 проверок.
Кол-во записей = порядка 100.
В этом случае лучше (или без разницы) сделать цикл по всем записям и делать все проверки по каждой записи.

Чем больше записей тем выгоднее переложить работу по работе с записями на СУБД.
Надеюсь так понятнее.
16 дек 03, 12:35    [461188]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
Varan
Member

Откуда:
Сообщений: 1258
Incold,
Я уж чувствую, что заразился этой напстью :-)
"число полей 15, нужно проверить 10 полей по 10 критериям - итого 100 проверок"
Все ж таки мне не совсем понятно, что понимается как "проверка по критерию"
Я под 1 проверкой имел в виду проверку одного значения одного поля.
А Вы?
Например мы имеем код типа такого, который возвращает результат проверки
Function Proverka(arg as string)as boolean
dim x1 as,X2 as ...
X1=f(arg)
select case X1
case Value_1
if ...
Proverka=...
else
end if
case value_2
if..
else
end if
case value_3

end select
end function
Это в Вашем понимании одна проверка или столько, сколько раз Case-ов и IF-ов в коде?
16 дек 03, 12:47    [461214]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
incold
Member

Откуда:
Сообщений: 1580
Ошибка:Должно быть 4 символа, а их 5

Кол-во проверок - это макисмальное число вот таких вот сообщений.
И еще, я указывал, что свой пример привожу для Transact-SQL
В MDB будет немного по другому.

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

Пример который был на кол-во символов в поле (Transact-SQL):

-- 1 проверка на все записи, чтобы число символов в поле не превышало 4


if exists(select * from tab1 where len(field1)>4) begin
insert into tab4 (id, name_field, message)
select id, 'field1', 'Ошибка: должно быть не более 4 символов'
from tab1 where len(field1)>4
end
else begin
-- Перенести записи, которые удовлетворяют условию

insert into tab2(id, field1)
select id, field1 from tab1 where len(field1)<=4
end
16 дек 03, 13:02    [461260]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
Varan
Member

Откуда:
Сообщений: 1258
incold ,
Спасибо, как попробую SQL-вариант, расскажу какой скоростнее для моих данных. Даже если он и будет медленнее, в следующий раз думать буду, прежде чем по клаве долбить
16 дек 03, 13:15    [461311]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
ASCRUS
Member

Откуда: МО Электросталь
Сообщений: 5994
А зачем дважды мучать SELECT проверки ? Предлагаю подредактировать пример:

-- Заносим ошибочные

insert into tab4 (id, name_field, message)
select id, 'field1', 'Ошибка: должно быть не более 4 символов'
from tab1 where len(field1)>4

-- Перенести записи, которые удовлетворяют условию, если ошибок нет

if @@ROWCOUNT = 0
insert into tab2(id, field1)
select id, field1 from tab1 where len(field1)<=4


Если требуется и в результате присутствия ошибок заносить верные данные в другую таблицу, то с скрипта нужно просто убрать IF.

Насчет проверок - в принципе смотря что и зачем проверяется. Если просто проверяются значения полей, то тут самое удобное воспользоваться от case в селектах для примитивных условий до проверяющих функций. Кстати в данном случае приведения примера лично я считаю особого выигрыша запроса у курсорного варианта не будет - в обоих случаях сервер проведет table scan - причем для варианта с запросом скорее всего table scan будет проведен дважды по таблице из за использования функции Len(), а в случае полного перебора таблицы курсором получится всего один раз. Так что тут как ни странно в данном случае наоборот - курсор будет быстрее.
16 дек 03, 13:56    [461473]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
Varan
Member

Откуда:
Сообщений: 1258
ASCRUS , спасибо.
Оказывается, "курсоры" - не всегда зло!
16 дек 03, 14:24    [461603]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
incold
Member

Откуда:
Сообщений: 1580
2 ASCRUS
Полностью согласен со всеми замечаниями ....
Но ведь это же был пример, чтобы объяснить смысл понятия курсоров...
хотя наверное не очень удачный.
16 дек 03, 14:24    [461605]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
ASCRUS
Member

Откуда: МО Электросталь
Сообщений: 5994
Ну тут как всегда все относительно :) Например если предположить, что на таблицы tab3 и tab2 существуют триггеры на добавление, то вариант с запросом однозначно будет быстрее, так как эти триггеры при запросе будут вызваны по одному разу для каждой таблицы и можно будет спокойно обработать весь набор вставленных записей с Inserted одним запросом. В случае же курсора получится, что триггера будут вызываться столько раз, сколько записей в обрабатываемой таблице, что в случае какой то сложной обработки в триггерах приведет к существенному замедлению. Плюс стоит учитывать особенности каждой СУБД - например я сейчас работаю в Sybase ASA, где можно создавать индексы на системные функции, т.е. там спокойно можно создать индекс на Len(Field1) и соотвествующе избавиться от TABLE SCAN, перейдя на INDEX SCAN. Плюс как ни странно, но за свою практику проектирования БД я сто процентно убедился, что частенько приходится логику и структуру БД подгонять под конкретные требования клиентских приложений, причем под Access это одно, под Delphi - другое. Единственный инструмент, который на моей памяти может работать с "чистой" структурой БД, без логики, специально ориентированной на него - это Power Builder, но к сожалению у нас он распостранен только в крупных конторах, предпочитающих западное ПО.

Так что мое личное мнение, что тут дело не сколько в курсорах, запросах и т.д., а в правильном понимании поставленной задачи архитектором БД, ее правильным решением с учетом самого ТЗ и использования сред разработки клиентских приложений. Например в приведенном в данном топике примере сразу возникает закономерный вопрос - зачем таблицу с данными разбивать на 2 таблицы, с правильными и ошибочными данными ? Не легче ли сделать просто таблицу с ключевым полем ID записи и в нее занести коды верных или ошибочных данных. Причем опять же, что лучше, стоит решать исходя из постановки задачи, чего меньше бывает в исходной таблице - верных или ошибочных записей. Если меньше ошибочных, то значит таблицу делаем для них:
insert into Errors (ID)

select ID
from Tab1
where Len(Field1) > 4

В итоге мы всегда можем быстро получить верные данные:
select *

from Tab1
where ID not in ( select ID from Errors )

и ошибочные записи:
select *

from Tab1
where ID in ( select ID from Errors )

В итоге мы имеем всего один table scan по таблице Tab1, не занимаем лишнего места в БД двумя дублирующими записями таблицами вместе с основной , соотвествующе не делали лишних накладных расходов по физической записи на диск данных этих таблиц, ну и всегда сможем быстро получить правильные и ошибочные записи, так как оптимизатор MSSQL будет использовать алгоритм сканирования первичного ключа таблицы Errors, а если там не так много записей, то фактически и вообще первым же запросом загоним ее в кэш MSSQL и уже в дальнейшей серии нужных нам запросов будем работать с ее копией в памяти.

Так что дело только в проектировании, знание релляционных основ, умение думать на SQL и мыслить абстрактно применительно к множествам.

P.S. Я в этом плане за название не "Курсорная болезнь", а "Алгоритмическая болезнь", которой очень часто подверженны программисты, привыкшие алгоритмически обрабатывать множества данных путем разбиения процесса обработки данных на серию мелких пошаговых алгоритмов. Особенно этой болезни насколько я знаю подверженны многие программисты, привыкшие пошагово работать с наборами данных: дельфийцы, фокспрошники, парадоксники и т.д. В этом плане программистам Access должно быть легче, так как изначально Jet-движок Access был настоящим SQL-движком и им более привычны понятия манипулирования данными с помощью запросов.
16 дек 03, 15:17    [461763]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
incold
Member

Откуда:
Сообщений: 1580
оффтопик

2 ASCRUS
Снимаю шляпу, и позвольте пожать Вашу руку
16 дек 03, 15:25    [461796]     Ответить | Цитировать Сообщить модератору
 Re: "Курсорная болезнь" - что это такое и как от нее избавиться  [new]
ASCRUS
Member

Откуда: МО Электросталь
Сообщений: 5994
incold
Большое спасибо :)

Я тут как бы оказался случаным гостем, по приглашению Varan, но в принципе темы проектирования БД для всех СУБД одинаковы, а вопрос оказался для меня интересным :) Мне кажется надо почаще такие вопросы выносить в форум "Проектирование БД", а то получается, что мы с вами живем на просторах одного сайта и почти никогда не пересекаемся, каждый обитая только в пределах своего рабочего форума. Я лично например очень частый гость и наблюдатель форума mssql, не смотря на то, что уже давно работаю не на нем, а Sybase ASA, и не только потому, что у этих СУБД много похожего, а именно из за обсуждаемых там вопросов и оригинальных решений, которые легко потом переводятся в плоскость собственной платформы разработки. Как говориться, своя каша конечно хорошо, но и не грех посмотреть, как коллеги других форумов кашу готовят :)
16 дек 03, 15:38    [461839]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft Access Ответить