Почему у меня есть 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))
Ответ 3
В соответствии с этим потоком (внизу), это может зависеть от вашего уровня совместимости:
http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/a874b4b2-05ad-4066-9811-30939188d695
Ответ 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). Это не повредит, если он включен, потому что он прекратит запрос, когда во время запроса возникает ошибка переполнения или деления на нуль выполнение.