TUniTable и CursorUpdate

Обсуждение возникших проблем, предложений и ошибок UniDAC компонентов
Закрыто
denzay.dp
Сообщения: 10
Зарегистрирован: Пт 11 апр 2014 15:14

TUniTable и CursorUpdate

Сообщение denzay.dp » Пт 11 апр 2014 15:51

Доброго времени суток.

Есть ли способ оптимизировать запрос на 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. 
(Остальное - по умолчанию).

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: TUniTable и CursorUpdate

Сообщение AndreyZ » Вт 15 апр 2014 14:53

Добрый день.
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', то все новые изменения данных для курсора недоступны.

denzay.dp
Сообщения: 10
Зарегистрирован: Пт 11 апр 2014 15:14

Re: TUniTable и CursorUpdate

Сообщение denzay.dp » Вт 15 апр 2014 16:40

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 эта запись, которую мы только что добавили, не видна. В гриде визуально запись исчезает, что выглядит как-то обескураживающе. После рефреша эта запись становится видна.

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: TUniTable и CursorUpdate

Сообщение AndreyZ » Ср 16 апр 2014 12:14

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 курсора не будут видны записи, которые были добавлены в других контекстах.

denzay.dp
Сообщения: 10
Зарегистрирован: Пт 11 апр 2014 15:14

Re: TUniTable и CursorUpdate

Сообщение denzay.dp » Вт 29 апр 2014 09:51

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

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: TUniTable и CursorUpdate

Сообщение AndreyZ » Вт 29 апр 2014 14:09

Мы исследовали проблему и изменим данное поведение в следующей версии UniDAC.

denzay.dp
Сообщения: 10
Зарегистрирован: Пт 11 апр 2014 15:14

Re: TUniTable и CursorUpdate

Сообщение denzay.dp » Вт 29 апр 2014 14:46

Когда, приблизительно, можно ждать релиза?

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: TUniTable и CursorUpdate

Сообщение AndreyZ » Ср 30 апр 2014 16:48

В новый билд UniDAC данное изменение не вошло. Изменение данного поведения будет доступно на следующей неделе.

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: TUniTable и CursorUpdate

Сообщение AndreyZ » Ср 07 май 2014 09:08

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

vfisher
Сообщения: 13
Зарегистрирован: Вт 06 май 2014 15:44

Re: TUniTable и CursorUpdate

Сообщение vfisher » Ср 15 июл 2015 14:15

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

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

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: TUniTable и CursorUpdate

Сообщение AndreyZ » Чт 16 июл 2015 10:56

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 тестовое приложение, на котором воспроизводится данная проблема. К приложению также добавьте скрипт для создания тестовой таблицы.

vfisher
Сообщения: 13
Зарегистрирован: Вт 06 май 2014 15:44

Re: TUniTable и CursorUpdate

Сообщение vfisher » Пн 20 июл 2015 09:41

Обновление всех полей курсора, вместо только измененных:
Изображение

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

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

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)
Тестовый проект во вложении.
Вложения
CursorBug.7z
(1.43 КБ) 201 скачивание

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: TUniTable и CursorUpdate

Сообщение AndreyZ » Пн 20 июл 2015 12:25

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

Закрыто