:: Архив конференции по VFP до 2005 года
Re: 100% загруженности SQL сервера 2000
PaulWist
Автор

Сообщений: 14585
Дата регистрации: 01.04.2004
Конечно , на T-SQL, поскольку SQLEXEC пересылает строку на выполнение (считай, что из QA выполняешь команду), другое дело, что можно использовать несколько подходов, что бы затолкать массив из 2000 элементов на сервер.




------------------
Есть многое на свете, друг Горацио...
Что и не снилось нашим мудрецам.
(В.Шекспир Гамлет)
Ratings: 0 negative/0 positive
Re: 100% загруженности SQL сервера 2000
WiRuc

Сообщений: 1012
Дата регистрации: 09.04.2002
Цитата:
Hi, WiRuc!
Ты считаешь что проще запихать кучу записей в базу именно через ХП? А если
СУБД не умеет XML парсить (или медленно/криво это делает), как ты туда целый
массив загонишь?

А что, RemoteView умеет вставлять кучу записей за раз? Только не надо про BatchUpdateCount, в любом случае будут оформляться отдельные Insert, только они будут объединены в один пакет. А его еще надо откомпилить, да и передать по сети.
Вызов ХП на вставку для каждой записи через RPC будет выгодней, чем вставка через RemoteView.
И не будем вспоминать про то, что ХП вообще то могут делать кучу работы внутри себя, не обмениваясь с клиентом промежуточными данными, что тоже сильно способствует ускорению работы. Ну, это основы построения клиент-сервера, думаю вы в курсе.

Применение RemoteView оправдано на мой взгляд только в следующих случаях:
1) Крупное многоплатформенное приложение, когда поддерживать нескольких версий серверной части становиться невыгодно.
2) Желание быстро портировать Фоксовое приложение на клиент-серверную основу.
3) В случае осуществления выборок со сложной динамической фильтрацией. На основе ХП это реализуется довольно тяжко, а вот на клиенте построить динамический селект проще простого.

Так что, все изменения БД должны вестись через ХП (тут возможен вариант с CursorAdapter и "ручным" оформлением команд на изменение БД с помощью ХП, хотя я использую класс на основе SQLEXEC), да и большая часть выборок тоже.
Все вышесказанное, естественно, IMHO.
Ratings: 0 negative/0 positive
Re: 100% загруженности SQL сервера 2000
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Hi, WiRuc!

Ну а как насчёт управления транзакциями? "Внешнее" управление позволит
сделать все изменения за 1 (ну пускай даже 1 на скажем 1000 INSERT-ов)
транзакцию, не потеряем ли мы этой возможности используя ХП?
А вообще все массовые операции практически на всех СУБД выполняются вовсе не
через SQL, а специализированными утилитами - bulk copy и т.п. Ибо скорости
там порой на несколько порядков большие...
И кстати чем тебя не устраивает SQLPREPARE() - AFAIK тогда тоже собственно
команда передаётся по сети и компилируется 1 раз, потом лишь параметры
качаются (т.е. реальные данные) и на сервере уже откомпилированная команда
исполняется.

Насчёт недостатков (ну точнее я например не знаю как это можно по
нормальному решить ни на MS SQL, ни на Oracle):
Предположим что у нас есть таблица - TestTable (n1 Int, c1 varchar(10), d1
DateTime)
На неё навешены Default-ы или триггера на вставку (в Oracle скажем
автонумерация из Sequence в триггере и подключается). И мы хотим вставить в
эту табличку НЕПОЛНЫЕ данные - например у 10 записей нету n1 (надо чтоб
сработал Default или триггер), ещё у 10 нету c1 у каких-то нету И с1 И n1 ну
и т.д.
Если это делать со стороны фокса, то анализируя поля на EMPTY() можно в
одном случае сформировать команду
INSERT INTO TestTable (n1, c1, d1) VALUES (...)
в другом
INSERT INTO TestTable (c1, d1) VALUES (...)
А в третьем и вовсе
INSERT INTO TestTable (d1) VALUES (...)
И всё будет работать!
А вот как такого добиться используя ХП?
передавать NULL? Но тогда NULL и вставиться (если позволит поле), и Default
не сработает, и триггер (вполне справедливо) посчитает что значение поля
таки БЫЛО явно задано...
Анализировать в ХП все параметры и по этому анализу "внутри" формировать
один из вышеуказанных вариантов? Но тогда представим таблицу с 50-ю полями и
"окинем взглядом" получившийся код
Учитывая что при Update возникают примерно такие-же проблемы, становится
совсем печально

Подскажи, как же ты выходишь из подобных ситуаций?




------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: 100% загруженности SQL сервера 2000
WiRuc

Сообщений: 1012
Дата регистрации: 09.04.2002
Цитата:
Ну а как насчёт управления транзакциями? "Внешнее" управление позволит
сделать все изменения за 1 (ну пускай даже 1 на скажем 1000 INSERT-ов)
транзакцию, не потеряем ли мы этой возможности используя ХП?

Ну, вообще-то я считаю, что управлением транзакциями должна заниматься серверная часть. Т.е. клиент стартует ХП, она открывает транзакцию, делает какие-то действия и закрывает или откатывает транзакцию.
В MSSQL управление транзакциями с клиента вообще подобно самоубийству, например, открыли документ на редактирование - открыли транзакцию минут эдак на 10 и пошли блокировки на все и вся.
У Oracle, т.к. он версионник, с этим попроще, там можно такое практиковать, хотя это тоже не совсем хорошо.
Кроме того, такой подход позволяет, например при возникновении деадлока или обрыве соединения с сервером, просто перезапустить ХП, не прерывая работу программы.
Конечно, бывают моменты, когда необходимо запускать транзакцию с клиента, но кол-во таких случаев необходимо минимизировать.

Цитата:
А вообще все массовые операции практически на всех СУБД выполняются вовсе не
через SQL, а специализированными утилитами - bulk copy и т.п. Ибо скорости
там порой на несколько порядков большие...

Естественно. И уж не через RemoteView однозначно...

Цитата:
И кстати чем тебя не устраивает SQLPREPARE() - AFAIK тогда тоже собственно
команда передаётся по сети и компилируется 1 раз, потом лишь параметры
качаются (т.е. реальные данные) и на сервере уже откомпилированная команда
исполняется.

Я уже приводил здесь результаты работы SQLPREPARE для MSSQL. После того, как я обнаружил эту "особенность", желание использовать SQLPREPARE у меня пропало.
Помимо этого, при использовании в качестве параметров сивольных строк происходит "засорение" кэша сервера.
Например, мы вызываем команду INSERT INTO table (name) VALUES (?m.cName), где cName - это символьная переменная.
В этом случае, для каждого размера переменной (длины строки) будет создан и сохранен в кэше собственный план. Т.е. для cName='a' - это один план, для cName='ab' - еще один план и т.д. для всех вариантов длины строки в переменной.
Это на MSSQL, не знаю, как обстоит с этим дело у Oracle.
И, напоследок, даже при вызовы через SQLPREPARE накладные раходы чуть выше, чем непосредственный RPC вызов ХП.

Цитата:
Насчёт недостатков (ну точнее я например не знаю как это можно по
нормальному решить ни на MS SQL, ни на Oracle):
Предположим что у нас есть таблица - TestTable (n1 Int, c1 varchar(10), d1
DateTime)
На неё навешены Default-ы или триггера на вставку (в Oracle скажем
автонумерация из Sequence в триггере и подключается). И мы хотим вставить в
эту табличку НЕПОЛНЫЕ данные - например у 10 записей нету n1 (надо чтоб
сработал Default или триггер), ещё у 10 нету c1 у каких-то нету И с1 И n1 ну
и т.д.
Если это делать со стороны фокса, то анализируя поля на EMPTY() можно в
одном случае сформировать команду
INSERT INTO TestTable (n1, c1, d1) VALUES (...)
в другом
INSERT INTO TestTable (c1, d1) VALUES (...)
А в третьем и вовсе
INSERT INTO TestTable (d1) VALUES (...)
И всё будет работать!
А вот как такого добиться используя ХП?
передавать NULL? Но тогда NULL и вставиться (если позволит поле), и Default
не сработает, и триггер (вполне справедливо) посчитает что значение поля
таки БЫЛО явно задано...
Анализировать в ХП все параметры и по этому анализу "внутри" формировать
один из вышеуказанных вариантов? Но тогда представим таблицу с 50-ю полями и
"окинем взглядом" получившийся код
Учитывая что при Update возникают примерно такие-же проблемы, становится
совсем печально

Подскажи, как же ты выходишь из подобных ситуаций?
О, это моя любимая тема
Один из самых значительных недостатков при использовании ХП.
Для вставки в принципе все довольно просто. Тут есть два варианта:
1) Т.к. ВСЕ изменения в БД делаются через ХП (в том числе и в высокоуровневых ХП), то DEFAULT вешаются не на таблицу, а на параметры ХП. В результате вызов ХП оформляется как UP_BASE_INSERT ?id,DEFAULT,?m.cName

2) В ХП на вставку фактически производится две операции: вставка и обновление. Т.е. сперва мы осущемствляем вставку с МИНИМАЛЬНО необходимым набором полей. После этого производится обновление записи для остальных полей.

insert into table (id) values (@id)
update table set name=isnull(@name,name)

Этот вариант помедленней первого, да и вообще похуже. Например, не допускает появления NULL в полях, а, если допускается, то тогда необходимо передавать маску обновлений в ХП.

Для UPDATE все гораздо хуже, хотя тут тоже возможны 3 варианта.
1) Не используем NULL в полях таблицы. В этом случае можно передавать в качестве параметра NULL для тех значений, которые не требуется обновлять.

update table set id=isnull(@id,id), name=isnull(@name,name)

2) Используем маску обновлений. Смысл в том, чтобы строить на клиенте битовую маску, в которой для тех значений, которые необходимо обновлять, ставим 1.
И в ХП, помимо самих значений полей, передаем еще и эту маску.

update table set id=(CASE WHEN GetUpdateBit(@updmask,1)=1 THEN @id ELSE id END), name=(CASE WHEN GetUpdateBit(@updmask,2)=1 THEN @name ELSE name END)

Ну, и конечно, есть третий вариант - использовать узкоспециализированные ХП, обновляющие 1-N... полей. Например, ХП обновляющая только цену и кол-во в строке спецификации документа.
Конечно, ни один из вариантов не идеален С другой стороны, если бы в жизни было все просто, тогда было бы совсем скучно
Ratings: 0 negative/0 positive
Re: 100% загруженности SQL сервера 2000
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Hi, WiRuc!

Цитата:
Ну, вообще-то я считаю, что управлением транзакциями должна
заниматься серверная часть
Я тоже так считаю, однако вот такой вот "массированный импорт" это как раз
исключение из правила - ну или нужно найти способ в ХП передать сразу
большой массив записей (не уверен, но наверное XML тут как раз подойдёт - но
вот сама ХП тогда может стать слишком уж сложной )
И конечно транзакция не должна "висеть"!
Цитата:
Я уже приводил здесь результаты работы SQLPREPARE для MSSQL
Я в курсе про этот баг, пока сам не использую активно, но что-то мне
подсказывает что долен быть способ обойти такое наглое поведение ODBC... Ибо
по всем правилам прекомпиляция должна ускорить работу
Цитата:
И, напоследок, даже при вызовы через SQLPREPARE накладные раходы чуть
выше, чем непосредственный RPC вызов ХП.
Не понимаю, там же вроде одинаковый объём инфы передаётся - те-же параметры
практически всё и съедают...
Цитата:
О, это моя любимая тема
;)
Цитата:
Один из самых значительных недостатков при использовании ХП.
Угу.
Цитата:
Для вставки в принципе все довольно просто. Тут есть два варианта:
1) Т.к. ВСЕ изменения в БД делаются через ХП (в том числе и в
высокоуровневых ХП), то DEFAULT вешаются не на таблицу, а на параметры
ХП
Хм, надо посмотреть как с этим у Oracle дела обстоят... Что-то меня терзают
смутные сомнения, что не очень хорошо там будет с этим вариантом
Цитата:
2) В ХП на вставку фактически производится две операции: вставка и
обновление. Т.е. сперва мы осущемствляем вставку с МИНИМАЛЬНО необходимым
набором полей. После этого производится обновление записи для остальных
полей.

insert into table (id) values (@id)
update table set name=isnull(@name,name)

Этот вариант помедленней первого, да и вообще похуже.
Да, именно про то я и говорю - NULL тут уже не NULL, а признак
"использования Default-а". Да и как тогда решить проблему с триггерами и
т.п. пакостями Ведь сработает эта зараза даже если Default на Default
менять А писать кучу "маленьких" UPDATE-ов (по одному полю за раз) внутри
соответствующих IF-ов совсем некрасиво получается
Цитата:
Например, не допускает появления NULL в полях, а, если допускается,
то тогда необходимо передавать
маску обновлений в ХП.
Вот вот - куча лишних телодвижений получается
Цитата:
Для UPDATE все гораздо хуже, хотя тут тоже возможны 3 варианта...
Конечно, ни один из вариантов не
идеален
Ты рассмотрел пока лишь трудности программирования собственно ХП - а ведь
всё это ещё как-то надо привязать к фоксу! И если Update и Insert он
автоматом строит вполне корректный, то отказ от прямых команд повлечёт
необходимость написания неслабого кода в BeforeUpdate/BeforeInsert для
CursorAdapter - ну или аналогичного кода при "ручном" управлении курсором
(не через CA). Конечно если не считать за разумный выход прописывание
УНИКАЛЬНОГО, т.е. неуниверсального кода в каждый такой управляющий объект,
или CA.
Цитата:
С другой стороны, если бы в жизни было все просто, тогда было бы
совсем скучно
Но и искать себе лишние сложности тоже не стоит




------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: 100% загруженности SQL сервера 2000
Владимир Максимов

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

Насколько часто встречается необходимость в таких массовых вставках? Есть ли смысл "копья ломать", если процесс относительно редок? Может пользователь согласен "потерпеть" или это можно решить организационно (например, перенести этот процесс на ночь или на выходные)?

Не знаю, как вы, но прежде чем отвечать на вопрос "Как?", я пытаюсь ответить на вопрос "А оно действительно нужно?"




------------------
Ratings: 0 negative/0 positive
Re: 100% загруженности SQL сервера 2000
PaulWist
Автор

Сообщений: 14585
Дата регистрации: 01.04.2004
2WiRuc

Прошу пояснить

Цитата:
1) Т.к. ВСЕ изменения в БД делаются через ХП (в том числе и в высокоуровневых ХП), то DEFAULT вешаются не на таблицу, а на параметры ХП. В результате вызов ХП оформляется как UP_BASE_INSERT ?id,DEFAULT,?m.cName

Если несколько ХП используют конкретную таблицу и нам необходимо использовать логику модификации, то возникает необходимость Default-ы прописывать в нескольких местах (ХП), вместо одного - у таблицы, на мой взгляд такой подход не совсем правильный.

Цитата:
Для UPDATE все гораздо хуже, хотя тут тоже возможны 3 варианта.
1) Не используем NULL в полях таблицы. В этом случае можно передавать в качестве параметра NULL для тех значений, которые не требуется обновлять.

Теоретически , поддерживаю такой подход, но практически не всегда можно этого добиться

Цитата:
2) Используем маску обновлений. Смысл в том, чтобы строить на клиенте битовую маску, в которой для тех значений, которые необходимо обновлять, ставим 1.
И в ХП, помимо самих значений полей, передаем еще и эту маску.

Вообщем-то выход.

А почему не использовать sp_executesql и динамически строить запрос на самом сервере.

Цитата:
3) В случае осуществления выборок со сложной динамической фильтрацией. На основе ХП это реализуется довольно тяжко, а вот на клиенте построить динамический селект проще простого.

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




------------------
Есть многое на свете, друг Горацио...
Что и не снилось нашим мудрецам.
(В.Шекспир Гамлет)
Ratings: 0 negative/0 positive


Извините, но у вас нет прав для того, чтобы оставлять сообщения в этом форуме.

On-line: 2 (Гостей: 2)

© 2000-2024 Fox Club 
Яндекс.Метрика