2009-07-08 1 views
13

Dlaczego muszę ustawić ARITHABORT ON podczas korzystania z xml w serwerze sql 2005? Próbowałem dowiedzieć się, dlaczego muszę to ustawić, ale nie mogłem znaleźć odpowiedzi, która by mi wyjaśniła dlaczego. Tyle, że trzeba to ustawić.Dlaczego muszę ustawić ARITHABORT ON podczas używania xml w serwerze sql 2005?

Oto konkretny komunikat o błędzie pojawia kiedy wyjąć ARITHABORT ustawiony na linii:

PARAMETER ERROR: INSERT LIST COULD NOT BE PARSED - INSERT failed because the following SET options have incorrect settings: 'ARITHABORT'. Verify that SET options are correct for use with indexed views and/or indexes on computed columns and/or query notifications and/or xml data type methods.

Moje procedura przechowywana działało dobrze sprawdził z ASP.NET za pomocą ODBC w jednym środowisku. Następnie, kiedy przeniosłem go do innego, musiałem dodać SET ARITHABORT ON na początku procedury przechowywanej. Załączam odpowiednie sekcje procedury składowanej poniżej. I kod, który go wywołuje.

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   

Wywołanie Kod

' 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) 

Odpowiedz

6

Myślę, że to stwierdzenie z książek online rodzaj wskazówek na ten temat: "SET ARITHABORT musi być ON podczas tworzenia lub zmiany indeksów na kolumnach obliczeniowych lub widoków indeksowanych." Tak więc metoda węzłów musi tworzyć wewnętrznie indeksowany widok lub coś takiego. Ale to tylko wykształcone przypuszczenie.

0

Chyba że tworzenie indeksów XML nie należy trzeba ustawić ARITHABORT ON. Powiedział, że wiem, że są pewne problemy z wydajnością podczas korzystania z ADO.NET (które moim zdaniem ustawia ARITHABORT na OFF) Nie boli mając go ON, ponieważ zakończy kwerendę, gdy wystąpi błąd przepełnienia lub dzielenia przez zero podczas kwerendy wykonanie.

4

Oto rozwiązanie, które znalazłem w przypadku ARITHABORT podczas wywoływania procedury składowanej z parametrem wejściowym xml z klienta .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)) 
+0

Nie można po prostu wyraźnie stwierdzają odpowiednie opcje w przechowywane proc? 'SET ANSI_NULLS ON SET ANSI_PADDING NA SET ANSI_WARNINGS NA SET ARITHABORT NA CONCAT_NULL_YIELDS_NULL SET SET ON NUMERIC_ROUNDABORT OFF SET QUOTED_IDENTIFIER ON' –

2

odpowiedzi będą Rickards' i John Gilmer są solidne. Odpowiedzieli na pytanie "dlaczego" i "kiedy". Rozwiążę nieco odpowiedź Johna:

Po prostu doświadczyłem tego samego problemu i zastanawiałem się, dlaczego ustawienie ARITHABORT ma znaczenie - zwłaszcza, że ​​mam identyczne oprogramowanie działające bez problemu na kilku innych serwerach. Korzystanie z dwóch różnych serwerów, wykonałem następujące:

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 

Okazuje się różnicę między dwoma serwerami jest poziom zgodności bazy danych:

80: Error 
100: Okay