Почему у меня есть SET ARITHABORT ON при использовании xml в sql server 2005?

Почему мне нужно установить ARITHABORT ON при использовании xml в sql server 2005? Я попытался выяснить, почему я должен установить это, но не смог найти ответ, который сказал мне, почему. Только это нужно установить.

Вот конкретное сообщение об ошибке, которое я получаю, когда вынимаю строку SET ARITHABORT ON:

ОШИБКА ПАРАМЕТРОВ: СПИСОК ВСТАВКИ НЕ МОЖЕТ БЫТЬ ПАРСИРОВАН - ВСТАВЬТЕ не удалось потому что следующие параметры SET имеют неправильные настройки: 'ARITHABORT. Убедитесь, что параметры SET верны для использования с индексированными представления и/или индексы на вычисленных столбцах и/или уведомлениях запроса и/или методы типа данных XML.

Моя хранимая процедура отлично работала от asp.net, используя odbc в одной среде. Затем, когда я переместил его в другой, мне пришлось добавить SET ARITHABORT ON в начале хранимой процедуры. Ниже перечислены соответствующие разделы хранимой процедуры. И код, который его вызывает.

CREATE PROCEDURE [dbo].[myproc]
   @ruserid             varchar(8),
   @folder_list         xml,
   @insert_list         xml
AS

SET NOCOUNT ON
SET ARITHABORT ON

DECLARE @rindex integer
DECLARE @errormsg nvarchar(4000)
DECLARE @folder_cnt integer
DECLARE @insert_cnt integer


SET @rindex = -1

-- temp table to hold inserts
CREATE TABLE #insert_list (rowidx integer IDENTITY(1,1), insertdesc varchar(96) COLLATE database_default, insertfolder integer)

-- temp table to hold folders
CREATE TABLE #folder_list (rowidx integer IDENTITY(1,1), folderdesc varchar(144) COLLATE database_default, insertfolder integer)

-- insert inserts to make sure data is compatible in type
BEGIN TRY
   INSERT INTO #insert_list (insertdesc, insertfolder)
   SELECT insert_list.listitem.value('@insertdesc', 'varchar(96)'), insert_list.listitem.value('@insertfolder', 'integer')
   FROM @insert_list.nodes('/Root/Insert') AS insert_list(listitem)
END TRY
BEGIN CATCH
   SET @errormsg = N'PARAMETER ERROR: INSERT LIST COULD NOT BE PARSED - ' + ERROR_MESSAGE()
   RAISERROR(@errormsg, 16, 1)
   RETURN
END CATCH

-- insert folders to make sure data is compatible in type
BEGIN TRY
   INSERT INTO #folder_list (insertfolder, folderdesc)
   SELECT folder_list.listitem.value('@insertfolder', 'integer'), folder_list.listitem.value('@folderdesc', 'varchar(144)')
   FROM @folder_list.nodes('/Root/Folder') AS folder_list(listitem)
END TRY
BEGIN CATCH
   SET @errormsg = N'PARAMETER ERROR: FOLDER LIST COULD NOT BE PARSED - ' + ERROR_MESSAGE()
   RAISERROR(@errormsg, 16, 1)
   RETURN
END CATCH

-- insert rows
BEGIN TRANSACTION

BEGIN TRY

INSERT INTO my_folder_request (ruserid)
VALUES ( @ruserid )

SET @rindex = SCOPE_IDENTITY()

INSERT INTO my_insert_request (rindex, insertdesc, insertfolder)
SELECT @rindex, #insert_list.insertdesc, #insert_list.insertfolder
FROM #insert_list
ORDER BY #insert_list.rowidx

INSERT INTO my_folder_desc (rindex, insertfolder, folderdesc)
SELECT @rindex, #folder_list.insertfolder, #folder_list.folderdesc
FROM #folder_list
ORDER BY #folder_list.rowidx

END TRY
BEGIN CATCH
   IF @@TRANCOUNT > 0
      ROLLBACK TRANSACTION
   SET @errormsg = N'DATA INSERTION FAILED WITH MESSAGE - ' + ERROR_MESSAGE()
   RAISERROR(@errormsg, 16, 1)
   RETURN
END CATCH

IF @@TRANCOUNT > 0
   COMMIT TRANSACTION

-- return result
SELECT @rindex AS rindex

DROP TABLE #insert_list
DROP TABLE #folder_list

GO           

Код вызова

  ' build odbc command for inserting creation request
  intRequestIndex = 0
  cmdAddRequest = New System.Data.Odbc.OdbcCommand
  cmdAddRequest.CommandType = CommandType.StoredProcedure
  cmdAddRequest.CommandTimeout = 60
  cmdAddRequest.CommandText = "{CALL myproc ( ?, ?, ?)}"

  ' add parameters to odbc command
  cmdAddRequest.Parameters.Add("@ruserid", OdbcType.VarChar, 8).Value = SafeODBCParamString(m_strUID)
  cmdAddRequest.Parameters.Add("@folder_list", OdbcType.NText).Value = System.Text.Encoding.Unicode.GetString(strmFolderList.ToArray())
  cmdAddRequest.Parameters.Add("@insert_list", OdbcType.NText).Value = System.Text.Encoding.Unicode.GetString(strmInsertList.ToArray())

  ' run odbc command returning info about results
  cmdAddRequest.Connection = Me.ODBCConnection()
  Try
     rdrRequestData = cmdAddRequest.ExecuteReader(CommandBehavior.CloseConnection) 

Ответы

Ответ 1

Я думаю, что это утверждение из книг в Интернете подсказывает: "SET ARITHABORT должен быть включен, когда вы создаете или меняете индексы на вычисленных столбцах или индексированных представлениях". Таким образом, метод узлов должен создавать внутренне или что-то вроде индексированного представления. Но это всего лишь образованная догадка.

Ответ 2

Здесь решение, которое я обнаружил при возникновении проблемы ARITHABORT при вызове хранимой процедуры с входным параметром xml от клиента .Net.

using (var conn = new SqlConnection(dbConnectionString))  
{  
    SqlCommand command = new SqlCommand("[stored procedure name here]", conn);  
    command.CommandType = CommandType.StoredProcedure;  
    command.Parameters.AddWithValue("@parameter_name", parameter_xml_value);  

    conn.Open();  

    SqlCommand arithabortCommand = new SqlCommand("SET ARITHABORT ON", conn);  
    arithabortCommand.ExecuteNonQuery();  

    command.ExecuteNonQuery();  
    conn.Close();  
} // using (var conn = new SqlConnection(dbConnectionString))  

Ответ 4

Ответы Рикардса и Джона Гилмера тверды. Они ответили "почему" и "когда". Я расскажу немного о Джоне:

Я только что испытал эту же проблему и задался вопросом, почему значение параметра ARITHABORT имеет значение, особенно потому, что у меня одинаковое программное обеспечение работает без проблем на нескольких других серверах. Используя два разных сервера, я выполнил следующее:

SET ARITHABORT OFF
DECLARE @message XML
SELECT @message = (SELECT '1' As Bar FOR XML PATH('Foo'), TYPE)
SELECT @@Version, @@Options, compatibility_level from sys.databases where name='xxxx'
SELECT @message.exist('/Foo/Bar') -- This line fails on only one server

Оказывается, разница между двумя серверами - уровень совместимости базы данных:

 80: Error
100: Okay

Ответ 5

Если вы не создаете индексы XML, вам не нужно устанавливать ARITHABORT в положение ON. Тем не менее, я знаю, что при использовании ADO.NET возникают некоторые проблемы с производительностью (которые, как я считаю, устанавливают ARITHABORT в OFF). Это не повредит, если он включен, потому что он прекратит запрос, когда во время запроса возникает ошибка переполнения или деления на нуль выполнение.