Страница 1 из 1

TUniTable и CursorUpdate

Добавлено: Пт 11 апр 2014 15:51
denzay.dp
Доброго времени суток.

Есть ли способ оптимизировать запрос на UPDATE, который делает TUniTable, путем уменьшения перечня обновляемых полей?
Суть проблемы: при обновлении одного поля из записи в TUniTable в профайлере виден запрос
exec sp_cursor 180150005,33,1,N'[TestTable]',@Field1=1,@Field2=2,@Field3='Test',@Notes=NULL.
т.е. UPDATE выполняется по всем полям. Если таблица имеет большое количество полей, то это не рационально.
На таблице висит триггер на UPDATE, который проверяет изменяемые значения каждого поля. Поскольку в вышеуказанном запросе участвуют все поля, мы имеем лишние проверки валидности значений полей, которые по факту не менялись.

Настройки TUniTable:

Код: Выделить всё

  SpecificOptions.Values['SQL Server.FetchAll']:= 'False';
  SpecificOptions.Values['SQL Server.CursorType']:= 'ctKeySet';
  SpecificOptions.Values['SQL Server.CursorUpdate']:= 'True';
Настрйоки TUniConnection:

Код: Выделить всё

  MultipleActiveResultSets = 'True'
  OLEDBProvider = 'prNativeClient'
Пробовал ставить SpecificOptions.Values['SQL Server.CursorUpdate']:= 'False', UPDATE выполняется только по измененному полю посредством запроса, но есть проблема: при создании новой записи (Append) и последующем сохранении - её нет в датасете.

Все остальные настройки - по умолчанию.
Используется UniDAC 5.2.7, MS SQL 2008 R2.

З.Ы. была замечена ошибка "Bookmark is invalid." после сохранения новой записи. при настройках

Код: Выделить всё

TUniTable: CursorType = ctStatic; 
CursorUpdate=True;
FetchAll=False. 
(Остальное - по умолчанию).

Re: TUniTable и CursorUpdate

Добавлено: Вт 15 апр 2014 14:53
AndreyZ
Добрый день.
denzay.dp писал(а):Есть ли способ оптимизировать запрос на UPDATE, который делает TUniTable, путем уменьшения перечня обновляемых полей?
При CursorUpdate = True для сохранения изменения данных мы используем интерфейс OLE DB, который требует явного заполнения всех полей таблицы, в противном случае незаполненные поля будут установлены в значение NULL. Мы не можем повлиять на это поведение OLE DB.
denzay.dp писал(а):Пробовал ставить SpecificOptions.Values['SQL Server.CursorUpdate']:= 'False', UPDATE выполняется только по измененному полю посредством запроса, но есть проблема: при создании новой записи (Append) и последующем сохранении - её нет в датасете.
Для серверного курсора типа ctKeySet записи, добавленные или удаленные другими пользователями недоступны для курсора. Для решения проблемы используйте тип серверного курсора 'ctDynamic' или клиентский курсор 'ctDefaultResultSet'. Подробнее о типах курсоров http://www.devart.com/sdac/docs/index.h ... ortype.htm
denzay.dp писал(а):З.Ы. была замечена ошибка "Bookmark is invalid." после сохранения новой записи. при настройках
TUniTable: CursorType = ctStatic;
Когда открыт серверный курсор 'ctStatic', то все новые изменения данных для курсора недоступны.

Re: TUniTable и CursorUpdate

Добавлено: Вт 15 апр 2014 16:40
denzay.dp
AndreyZ писал(а):При CursorUpdate = True для сохранения изменения данных мы используем интерфейс OLE DB, который требует явного заполнения всех полей таблицы, в противном случае незаполненные поля будут установлены в значение NULL. Мы не можем повлиять на это поведение OLE DB.
И при утсановке в TUniConnection OLEDBProvider в prNativeClient ситуация, судя по тестам, та же самая.
Но тем не менее ADO апдейтит только изменяемое поле из всей таблицы с помощью курсора и остальные поля записи в NULL не устанавливаются:

Код: Выделить всё

exec sp_cursor 180150003,33,1,N'TestTable',@Field3='Test'
Провайдер в TADOConnection установлен в Microsoft OLE DB Provider for SQL Server (в строке подключения - Provider=SQLOLEDB.1) остальное по умолчанию.

Настройки ADOTable:
CursorLocation = clUseServer
CursorType = ctKeyset
остальное по умолчанию.
AndreyZ писал(а): Для серверного курсора типа ctKeySet записи, добавленные или удаленные другими пользователями недоступны для курсора.
Имелось в виду, что обновление данных происходит в той же TUniTable при CursorUpdate = False. Post формирует не exec sp_cursor, а SQL запрос. При этом, если запись мы insert-им, то в TUniTable эта запись, которую мы только что добавили, не видна. В гриде визуально запись исчезает, что выглядит как-то обескураживающе. После рефреша эта запись становится видна.

Re: TUniTable и CursorUpdate

Добавлено: Ср 16 апр 2014 12:14
AndreyZ
denzay.dp писал(а):И при утсановке в TUniConnection OLEDBProvider в prNativeClient ситуация, судя по тестам, та же самая.
UniDAC работает и c SQL Native Client provider через OLE DB интерфейс, поэтому поведение одинаковое.
denzay.dp писал(а):Но тем не менее ADO апдейтит только изменяемое поле из всей таблицы с помощью курсора и остальные поля записи в NULL не устанавливаются:
Спасибо за информацию. Мы будет исследовать это поведение и сообщим вам о результатах.
denzay.dp писал(а):Имелось в виду, что обновление данных происходит в той же TUniTable при CursorUpdate = False. Post формирует не exec sp_cursor, а SQL запрос. При этом, если запись мы insert-им, то в TUniTable эта запись, которую мы только что добавили, не видна. В гриде визуально запись исчезает, что выглядит как-то обескураживающе. После рефреша эта запись становится видна.
При опции SpecificOptions.Values['SQL Server.CursorType']:= 'ctKeySet' TUniTable работает с контекстом серверного KeySet курсора.

При CursorUpdate = True для вставки записи TUniTable выполняет команду "exec sp_cursor", которая вносит изменения в контекст самого курсора.

При CursorUpdate = False для вставки записи TUniTable выполняет команду 'exec sp_executesql', которая вносит изменения в таблицу, но не изменяет контекст курсора.

Согласно спецификации MSDN, в контексте KeySet курсора не будут видны записи, которые были добавлены в других контекстах.

Re: TUniTable и CursorUpdate

Добавлено: Вт 29 апр 2014 09:51
denzay.dp
AndreyZ писал(а): Спасибо за информацию. Мы будет исследовать это поведение и сообщим вам о результатах.
Есть ли какие-то результаты по этому вопросу?

Re: TUniTable и CursorUpdate

Добавлено: Вт 29 апр 2014 14:09
AndreyZ
Мы исследовали проблему и изменим данное поведение в следующей версии UniDAC.

Re: TUniTable и CursorUpdate

Добавлено: Вт 29 апр 2014 14:46
denzay.dp
Когда, приблизительно, можно ждать релиза?

Re: TUniTable и CursorUpdate

Добавлено: Ср 30 апр 2014 16:48
AndreyZ
В новый билд UniDAC данное изменение не вошло. Изменение данного поведения будет доступно на следующей неделе.

Re: TUniTable и CursorUpdate

Добавлено: Ср 07 май 2014 09:08
AndreyZ
Если вы хотите получить данное изменение - пришлите свой e-mail и лицензию на andreyz*devart*com и мы вышлем вам специальный билд.

Re: TUniTable и CursorUpdate

Добавлено: Ср 15 июл 2015 14:15
vfisher
6.1.4 17-Jun-15
...
Bug with unnecessary update of all fields when a server cursor is used is fixed
Текущая версия 6.1.6, то же окружение. Баг как был, так и остался. Годичный юбилей уже отпраздновали.

Тестовое приложение необходимо?

Re: TUniTable и CursorUpdate

Добавлено: Чт 16 июл 2015 10:56
AndreyZ
vfisher писал(а):6.1.4 17-Jun-15...Bug with unnecessary update of all fields when a server cursor is used is fixed
Мы не можем воспроизвести указанный вами баг на текущей версии UniDAC 6.1.6 . Мы также попытались воспроизвести его на тестовом примере, который нам присылал denzay.dp, однако баг не воспроизвелся.

Пожалуйста, пришлите мне на почту andreyz*devart*com тестовое приложение, на котором воспроизводится данная проблема. К приложению также добавьте скрипт для создания тестовой таблицы.

Re: TUniTable и CursorUpdate

Добавлено: Пн 20 июл 2015 09:41
vfisher
Обновление всех полей курсора, вместо только измененных:
Изображение

Хитрость получения ошибки в том, что нужно дважды клацнуть на чекбокс, тем самым вернув его к первоначальному значению.
Несмотря на то, что значение поля не изменилось (первое), и меняли мы всего одно поле в записи (второе), мы имеем запрос

Код: Выделить всё

exec sp_cursor 180150003,33,1,N'[test1]',@pkey=1,@val1=100500,@val2=1
Воспроизводится стабильно на 6.1.6 и всех более ранних, Delphi XE, SQL Server 2008.
Таблицу и данные создаем так:

Код: Выделить всё

CREATE TABLE test1(
  pkey INT PRIMARY KEY,
  val1 INT,
  val2 bit
)

INSERT INTO test1(pkey, val1, val2)
VALUES(1, 100500, 1)
Тестовый проект во вложении.

Re: TUniTable и CursorUpdate

Добавлено: Пн 20 июл 2015 12:25
AndreyZ
Если ни одно поле записи не было изменено, то при вызове метода Post UniDAC формирует SQL запрос, который явно изменяет значения всех полей. При этом может возникнуть ситуация, когда на момент вызова Post для серверного курсора эта запись уже удалена другим пользователем. В этом случае сервер вернет ошибку. Если же UniDAC не будет вызывать запрос, то пользователь не узнает, что запись была удалена. Т.е. такое поведение является корректным.