2012-09-05 3 views
1

오류를 무작위로 발생시키는 일부 코드를 프로덕션에 출시했습니다. 나는 이미 질문을하는 방식을 완전히 바꾸어서 문제를 해결했다. 그러나, 그것은 내가 처음에 문제를 일으킨 것이 무엇인지 모르기 때문에 누군가가 대답을 알 수 있는지 궁금해했다. 저장 프로 시저 내부에 다음과 같은 쿼리가 있습니다. 나는 중첩 된 함수 호출과 그런 식으로 쿼리를 작성하는 것은 좋은 습관이 아니라는 코멘트를 찾고 있지 않다. 왜 그것이 일관되게 작동하지 않는지 알아 내고 싶습니다. 무작위로 쿼리의 함수는 숫자가 아닌 값을 반환하고 조인에 오류가 발생합니다. 그러나 즉시 쿼리를 다시 실행하면 정상적으로 작동합니다. 당신이 가입주의 경우SQL Server 2008의 결과가 일치하지 않습니다.

SELECT  cscsf.cloud_server_current_software_firewall_id, 
       dbo.fn_GetCustomerFriendlyFromRuleName(cscsf.rule_name, np.policy_name) as rule_name, 
       cscsf.rule_action, 
       cscsf.rule_direction, 
       cscsf.source_address, 
       cscsf.source_mask, 
       cscsf.destination_address, 
       cscsf.destination_mask, 
       cscsf.protocol, 
       cscsf.port_or_port_range, 
       cscsf.created_date_utc, 
       cscsf.created_by 
    FROM  CLOUD_SERVER_CURRENT_SOFTWARE_FIREWALL cscsf 
    LEFT JOIN CLOUD_SERVER cs 
    ON   cscsf.cloud_server_id = cs.cloud_server_id 
    LEFT JOIN CLOUD_ACCOUNT cla 
    ON   cs.cloud_account_id = cla.cloud_account_id 
    LEFT JOIN CONFIGURATION co 
    ON   cla.configuration_id = co.configuration_id 
    LEFT JOIN DEDICATED_ACCOUNT da 
    ON   co.dedicated_account_id = da.dedicated_account_id 
    LEFT JOIN CORE_ACCOUNT ca 
    ON   da.core_account_number = ca.core_account_id 
    LEFT JOIN NETWORK_POLICY np 
    ON   np.network_policy_id = (select dbo.fn_GetIDFromRuleName(cscsf.rule_name)) 
    WHERE  cs.cloud_server_id = @cloud_server_id 
    AND   cs.current_software_firewall_confg_guid = cscsf.config_guid 
    AND   ca.core_account_id IS NOT NULL 
    ORDER BY cscsf.rule_direction, cscsf.cloud_server_current_software_firewall_id 

ON   np.network_policy_id = (select dbo.fn_GetIDFromRuleName(cscsf.rule_name)) 

는 함수를 호출합니다. 마지막으로이 함수를 호출

ALTER FUNCTION [dbo].[fn_SplitGetNthRow] 
(
    @sInputList  varchar(MAX), 
    @sDelimiter  varchar(10) = ',', 
    @sRowNumber  int = 1 
) 
RETURNS varchar(MAX) 
AS 
BEGIN 
    DECLARE  @value  varchar(MAX) 

    SELECT  @value = data_split.item 
         FROM 
         (
          SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) as row_num FROM dbo.fn_Split(@sInputList, @sDelimiter) 
         ) AS data_split 
         WHERE 
         data_split.row_num = @sRowNumber 

    IF   @value IS NULL 
     SET  @value = '' 

    RETURN  @value 
END 

:이 함수를 호출

ALTER FUNCTION [dbo].[fn_GetIDFromRuleName] 
(
    @rule_name    varchar(100) 
) 
RETURNS varchar(12) 
AS 
BEGIN 
    DECLARE  @value  varchar(12) 

     SET @value = dbo.fn_SplitGetNthRow(@rule_name, '-', 2) 
     SET @value = dbo.fn_SplitGetNthRow(@value, '_', 2) 
     SET @value = dbo.fn_SplitGetNthRow(@value, '-', 1) 

    RETURN  @value 
END 

: 여기

그 기능입니다

ALTER FUNCTION [dbo].[fn_Split] (
    @sInputList VARCHAR(MAX), 
    @sDelimiter VARCHAR(10) = ',' 
) RETURNS @List TABLE (item VARCHAR(MAX)) 
BEGIN 
    DECLARE @sItem VARCHAR(MAX) 
    WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0 
     BEGIN 
      SELECT @sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,@sInputList,0)-1))), @sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),LEN(@sInputList)))) 
      IF LEN(@sItem) > 0 
       INSERT INTO @List SELECT @sItem 
     END 

    IF LEN(@sInputList) > 0 
     INSERT INTO @List SELECT @sInputList -- Put the last item in 
    RETURN 
END 
+0

np.network_policy_id의 데이터 유형은 무엇입니까? –

+0

여기서 암묵적인 숫자 변환을 처리하고 있습니다. 이 함수는'varchar (12)'데이터 형을 반환하고 udf에서 문자열 조작을 수행하므로 숫자가 아닌 데이터를 가져올 가능성이 있으며 반환 데이터가 숫자인지 확인하기 위해 유효성 검사를 수행하지 않습니다 (가정 그게 네가 원하는 것). 따라서 조인 오류. – Kash

+0

np.network_policy_id는 int입니다. 함수가 정수로 변환 할 수없는 varchar (12)를 반환하기 때문에 오류가 발생한다는 것을 알고 있습니다. 특히이 함수는 'NPG'값을 반환합니다. 내가 이해할 수없는 것은 왜 그것이 무작위로 다른 것을 돌려 보내는 이유입니다. –

답변

6

그것이 이유를 "무작위로"반환 SQL Server가 쿼리를 최적화하는 방법과 단락이 발생하는 곳과 다른 점이 있습니다.

on np.network_policy_id = (select case when isnumeric(dbo.fn_GetIDFromRuleName(cscsf.rule_name)) = 1) 
             then dbo.fn_GetIDFromRuleName(cscsf.rule_name) end) 

근본적인 문제는 평가의 순서입니다 : 조인 조건을 변경,

return (case when isnumeric(@value) then @value end) 

또는 : 문제를 해결하기 위해

한 가지 방법은 변화 fn_GetIDFromRuleName의 반환 값입니다. "case"문이 문제를 해결하는 이유는 변환하기 전에 숫자 값을 확인하기 때문입니다. SQL Server는 case 문에서 평가 순서를 보장합니다. 참고로 숫자가 아닌 "6e07"또는 "1.23"과 같은 숫자를 변환 할 때 여전히 문제가있을 수 있지만 정수는 아닙니다.

왜 가끔 작동합니까? 분명히 쿼리 실행 계획이 정적 또는 동적으로 변경되고 있습니다. 실패한 경우는 WHERE 조건에 의해 제외 된 행에있을 것입니다. 전환을 시도하는 이유는 무엇입니까? 문제는 전환이 발생하는 곳입니다.

변환은 쿼리 계획에 따라 다릅니다. 이것은 문제의 테이블 cscf가 언제 읽히는 지에 따라 달라질 수 있습니다. 이미 구성원 인 경우, 조회에서 첫 x 째 단계로 변환되어 읽 t 시도 될 수 있습니다. 그러면 오류가 발생합니다. 다른 시나리오에서는 다른 테이블이 필터링되고 행이 변환되기 전에 제거 될 수 있습니다. 어떤 경우

, 내 조언은 다음과 같습니다

  • 쿼리에서 암시 적 변환을하지 마십시오.
  • 명시 적 변환의 경우 case 문을 사용하십시오.
  • 변환 작업을 위해 데이터를 필터링하기 위해 WHERE 절에 의존하지 마십시오. case 문을 사용하십시오.