반응형

SP는 최초(처음) 실행 하는 시점에 실행계획을 수립하고 이후에는 실행계획을 계속 재사용 하게 됩니다

(이것이 SP를 사용하는 중요한 이유 중 하나 입니다).

이 최초 실행계획 수립시, 인수로 넘겨진 파라미터(매개변수)를 기준으로 통계를 통해 예상 행수를 추측하게 됩니다.

그런데 넘겨진 파라미터가 아닌 로컬 변수를 이용해서 쿼리를 실행하면 옵티마이저가 행수 추측이 실패하게 되어

원하지 않는 실행 계획이 생성 될 수 있습니다.

이로 인하여 SP 성능이 저하 될 수 있습니다.

 

예를 들어 다음과 같이 SP 가 되어 있을 때,

create proc Proc1 (
@p_date varchar(8)
)
as
SELECT
   *
FROM 
   SDSaleMaster a
WHERE
   a.SaleDate = @p_date

SP를 호출 하면,

EXEC Proc1 @p_date = '20190601'

실행계획에서 행수를 1326으로 예측 합니다.

이는 통계와 일치하는 제대로 된 예상 행 수 이기 때문에, 실행계획이 적합하게 나올 가능성이 높습니다.

그런데 다음과 같이 매개변수가 아닌 로컬 변수를 사용 하게 되어 있을 때,

create proc proc1 (
@p_date varchar(8)
)
as
declare
   @v_date varchar(8)

set @v_date = convert(varchar(8), dateadd(d, -1, @p_date), 112)  -- 하루 전

SELECT
   *
FROM 
   SDSaleMaster a
WHERE
   a.SaleDate = @v_date

SP를 호출 하면,

 EXEC Proc1 @p_date = '20190602'

옵티마이저가 예상 행수를 제대로 추정할 수가 없어서 549로 나오는 데, 이는 해당 테이블의 평균 밀도값을 이용한 것 입니다.

평균밀도

예상 행수 = 밀도 * 테이블 전체 row 수

 

이 글이 도움이 되셨으면 좋아요 눌러 주시거나 댓글을 남겨 주세요.

반응형
반응형

SQL 서버에서 서로 다른 데이터 타입간에 연산을 하게 되면
연산 전에 데이터 형식을 묵시적으로 형변환하게 되며,
이는 최종 결과 값의 데이터 형식이 된다.
그런데 여기에는 우선순위가 있기 때문에 때때로 연산결과 값에서 소수점이 사라지거나 오차가 발생 할 수 있으므로 주의해야 한다.

우선순위는 다음과 같다 (참조: https://docs.microsoft.com/ko-kr/sql/t-sql/data-types/data-type-precedence-transact-sql?view=sql-server-2017)

  1. 사용자 정의 데이터 형식(가장 높음)
  2. sql_variant
  3. xml
  4. datetimeoffset
  5. datetime2
  6. datetime
  7. smalldatetime
  8. date
  9. time
  10. float
  11. real
  12. decimal
  13. money
  14. smallmoney
  15. bigint
  16. int
  17. smallint
  18. tinyint
  19. bit
  20. ntext
  21. text
  22. image
  23. timestamp
  24. uniqueidentifier
  25. nvarchar(nvarchar(max) 포함)
  26. nchar
  27. varchar (varchar(max) 포함)
  28. char
  29. varbinary (varbinary(max) 포함)
  30. binary(가장 낮음)

그리고 피연산자에 숫자 상수값이 들어가는 경우 상수의 표현 방식에 따라 데이터형이 결정 되므로 역시 주의 해야 한다.

  1. 이진상수 : 0x 접미사 (16진수)
  2. integer 상수: 소수점 없는 정수
  3. 10진수(decimal, numeric) 상수: 숫자에 소수점이 포함
  4. float 및 real 상수: 과학 표기법 (예: 0.5E-1)

함수의 결과 값도 원래 컬럼의 데이터타입과 다른 경우가 있으므로 주의 해야 한다.
  1. SUM() :  decimal에 대한 계산 결과는 무조건 decimal(38, s) 가 된다.
                 s는 원래 decimal 타입 값의 소수점이하 자리 수.
                 전체 자리수가 무조건 38이 되므로 주의!
  2. CEILING(), FLOOR() : decimal에 대한 결과는 decimal(p, 0)이 된다.
                                p는 원래 decimal 타입 값의 전체 자리 수.

decimal 타입간의 연산 결과는 두 decimal 타입 중 더 넓은 범위의 값을 저장할 수 있는 타입이 우선순위를 가지는 것으로 보인다.
예를 들어 decimal(38, 5) 와 decimal(38, 2) 의 결과는 decimal(38, 2)로 된다.
소수점 이하 정밀도 보다는 정수 부분이 더 큰/작은 넓은 범위의 숫자를 저장할 수 있는 타입에 우선순위가 있는  것 같다.
특히 decimal에 대한 SUM()의 결과는 무조건 decimal(38, s)이 되고 CEILING()은 decimal(p, 0)이 되므로
만약 SUM()에 의하여 decimal(38, 5)가 되고, CEILING()에 의해 decimal(38, 0)이 된 경우 그 결과는 decimal(38, 0)이 되어
데이터에서 소수점이하 값이 사라질 수 있으므로 주의 해야 한다.

SELECT * 
INTO   #c 
FROM   (SELECT Sum(CONVERT(DECIMAL(38, 5), 123.45)) AS x 
        UNION 
        SELECT Ceiling(CONVERT(DECIMAL(38, 5), 456.78)) AS x) a 
go 

SELECT * 
FROM   #c 



반응형
반응형

윈도우 환경에서 Oracle Client 설치를 해도 ADO를 이용한 접속이 제대로 안되는 경우가 있다.

TNS, 포트 등 기본적인 설정상의 문제가 아니라면 다음을 확인 해보자.

 

1) OraOLEDB.Oracle 경우

 

접속 문자열에서 Provider를 'OraOLEDB.Oracle' 로 지정한 경우 시스템에 'Oracle Provider for OLE DB' 공급자가 정상적으로 등록되어 있어야 한다. 

 

등록여부는 다음과 같이 확인 할 수 있다.

 

1. 확장자 'UDL'로 임의의 파일을 생성 한다.

2. 해당 파일의 속성 창에서 '공급자' 페이지를 확인 한다.  

만약 위와 같이 'Oracle Provider for OLE DB' 가 나타나지 않으면 Oracle 사이트에서 ODAC를 받아서 설치를 한다. 

(http://www.oracle.com/technetwork/topics/dotnet/downloads/index.html) 

그런데 기존에 Oracle client 설치시 함께 설치를 했는데도 나오지 않는 경우에는 regsvr32 명령으로 OraOLEDB11.dll(11g 기준)을 레지스트리에 다시 등록을 해 본다.

만약 ODAC를 기존 Oracle client와 다른 별도의 경로에 설치 한 경우, network\admin\tnsnames.ora 파일에 TNS를 등록해야 한다.
그리고 32비트, 64비트용이 각각 존재 하므로 만약 64비트 윈도우즈 환경에서 32비트 프로그램이 Oracle 접속이 되지 않는다면
32비트 ODAC의 설치가 필요 하다.

참고로 공급자에 제대로 등록이 되어 있지 않은 상태에서 Oracle 접속을 시도할 경우 경우 다음과 같은 오류가 발생 한다. 

2) MSDAORA.1 경우

접속 문자열에서 Provider를 'MSDAORA.1'로 지정한 경우 시스템에 'Microsoft OLE DB Provider for Oracle' 공급자가 정상적으로 등록되어 있어야 한다. 위와 동일한 방법으로 확인 할 수 있다. 

그런데 MSDAORA는 32비트에서만 제공된다. 64비트에서는 더 이상 지원이 안되기 때문에 사용할 수가 없다.

처음에 이것을 몰라서 엄청 애를 먹었다. 꼭 Provider를 MSDAORA를 사용 해야 한다면 어플리케이션을 32비트로 컴파일 해서 사용하고 그렇지 않으면 OraOLEDB.Oracle 를 대신 사용해야 한다.

참고로 공급자에 제대로 등록이 되어 있지 않은 상태에서 Oracle 접속을 시도할 경우 경우 다음과 같은 오류가 발생 한다. 
어떤 경우에 아래와 같이 각각 다른 형태의 메시지가 나타나는 지는 알 수가 없었다.
 

 

이 글이 도움이 되셨으면 댓글을 남겨 주세요!

 
반응형
반응형
SQL서버 2012 이후 새로운 함수가 추가 되었는데 잘 모를 수 있어서 
공유하니 개발시에 도움되기 바랍니다.

1. 월의 마지막 일자

이전에는 월의 마지막 일자를 구하기 위하여 이런식 비슷하게 사용했을 것이다.
(여기서는 전월의 마지막 일자)


SELECT CONVERT(VARCHAR(8), DATEADD(D, -1, CONVERT(VARCHAR(6), GETDATE(), 112) + '01'), 112)

 

SQL서버 2012이후 제공되는 EOMONTH, FORMAT 함수를 이용하면 간단히 다음과 같이 할 수 있다.


SELECT FORMAT(EOMONTH(getdate(), -1), 'yyyyMMdd')



2. 숫자에 천단위 표시

위에서 이미 사용해 본 FORMAT 함수를 이용하면 된다.

SELECT FORMAT(123456789, '#,#'



​3. CASE​를 간단하게

아래 쿼리를 

SELECT  CASE DATEPART(WEEKDAY, GETDATE())

                                WHEN 1 THEN '일요일'

                                WHEN 2 THEN '월요일'

                                WHEN 3 THEN '화요일'

                                WHEN 4 THEN '수요일'

                                WHEN 5 THEN '목요일'

                                WHEN 6 THEN '금요일'

                                WHEN 7 THEN '토요일'

                     END

 

CHOOSE함수를 이용해서 다음과 같이 간단하게 구현할 수 있다.


SELECT CHOOSE(DATEPART(WEEKDAY, GETDATE())                     

    , '일요일','월요일','화요일','수요일','목요일','금요일','토요일')

 


​4. 이건 2012에 추가된 것은 아니지만 기억상실증을 예방 하기 위하여...

문자열이 날짜인지, 숫자인지 확인하는 함수

SELECT ISDATE('20161032'), ISDATE('20161031')

SELECT ISNUMERIC('123'), ISNUMERIC('a123'), ISNUMERIC('123a')

 


반응형

+ Recent posts