identity 속성인 컬럼의 경우 일반적으로 데이터를 지워도 지운 값을 비워두고 계속 사용하게 되는데 이 기사는 그 빈값을 재사용하는 방법에 대한 내용이다.

 

출처 : http://www.sqlservercentral.com/columnists/dPriyankara/reuseidentities.asp

---------------------------------------------------------------

 

What is the best way to Find and reuse deleted identities

 

By: Dinesh Priyankara

In most table designs, Identity columns are used to maintain the uniqueness of records. There is no problem with insertion and modification of data using an identity column. With deletions though, gaps can occur between identity values. There are several ways to reuse these deleted (removed) identity values. 

You can find a good solution in Books Online but I wanted to find a new way and my research ended up with a good solution. After several comparisons, I decided to continue with my solution. So, I'd like to share my method with you all and let you decide what solution to use.


First of all, let’s create a table called  ‘'OrderHeader'’ that has three columns. Note that the first column intID is identity type column.
 

IF OBJECT_ID('OrderHeader') IS NOT NULL
     DROP TABLE OrderHeader
GO
CREATE TABLE OrderHeader
(intID int IDENTITY(1,1) PRIMARY KEY,
strOrderNumber varchar(10) NOT NULL,
strDescription varchar(100))
 

Now let’s add some records to table. If you want, you can add small amount of records but I added 10000 records because most tables have more than 10000 records and we must always try to make our testing environment real.
DECLARE @A smallint
SET @A = 1
WHILE (@A <> 10001)
BEGIN
     INSERT INTO OrderHeader
          (strOrderNumber,
          strDescription)
          VALUES
          (‘OD-' + CONVERT(varchar(3), @A), -- Adding something for Order Number
          'Description' + CONVERT(varchar(3), @A)) -- Adding something for Description
     SET @A = @A + 1
END 

OK. Let’s delete some randomly selected records from the table.

DELETE OrderHeader WHERE intID = 9212
DELETE OrderHeader WHERE intID = 2210
DELETE OrderHeader WHERE intID = 3200
 
If you run now a simple select query against the table, you will see some gaps between the column intID values.

Now it is time to find these gaps and reuse. As I mentioned above there are two methods (or more methods if you have already done in some other way). First let’s see the BOL example.


Method 1

DECLARE @NextIdentityValue int

SELECT @NextIdentityValue = MIN(IDENTITYCOL) + IDENT_INCR('OrderHeader')
FROM OrderHeader t1
WHERE IDENTITYCOL BETWEEN IDENT_SEED('OrderHeader') AND 32766
    AND NOT EXISTS (SELECT * FROM OrderHeader t2
        WHERE t2.IDENTITYCOL = t1.IDENTITYCOL + IDENT_INCR('OrderHeader'))

SELECT @NextIdentityValue AS NextIdentityValue

Output:
NextIdentityValue
--------------------
2210
 

This is very simple query. You can find the first deleted identity value and can reuse it. But remember you have to set the IDENTITY_INSERT ON that is allowed to explicit values to be inserted into identity column.

SET IDENTITY_INSERT OrderHeader ON

INSERT INTO OrderHeader
    (intID,
    strOrderNumber,
    strDescription)
VALUES
    (@NextIdentityValue,
    ‘OD-' + CONVERT(varchar(3), @A),
    'Description' + CONVERT(varchar(3), @A))

SET IDENTITY_INSERT OrderHeader OFF
 
Now let’s see the method 2.

Method 2 

Now I am going to create another table that is called “tb_Numbers” and has only one column that contains numbers in sequence. In my most databases, I have created and used this table for many tasks. Let me come with those in my future articles.

IF OBJECT_ID('tb_Numbers') IS NOT NULL
    DROP TABLE tb_Numbers
GO
CREATE TABLE tb_Numbers
(intNumber int PRIMARY KEY)
 

Note that I have inserted 30000 records (numbers) into the table. The range is depending on the usage of this table. In my some of databases, this range was 1 to 1000000.

DECLARE @A1 int
SET @A1 = 1

WHILE (@A1 <> 30000)
BEGIN
    INSERT INTO tb_Numbers (intNumber) VALUES (@A1)
    SET @A1 = @A1 + 1
END
 

Now let’s query the gaps (or first deleted identity value) in the OrderHeader table

SELECT TOP 1 @NextIdentityValue = intNumber
FROM OrderHeader
    RIGHT OUTER JOIN tb_Numbers
    ON tb_Numbers.intNumber = OrderHeader.intID
WHERE intID IS NULL AND intNumber < = (SELECT MAX(intID) FROM OrderHeader)

SELECT @NextIdentityValue AS NextIdentityValue
Output:
NextIdentityValue
--------------------
2210
 

This is very simple query too. I have used RIGHT OUTER JOIN to join the OrderHeader table with tb_Numbers. This join causes to return all rows (numbers) from tb_Numbers table. Then I have used some search conditions (WHERE clauses) to get the correct result set.  This result set contains all missing values in intID column.  By using TOP 1, we can get the desired result.

You can do the insertion same way as I have done in method 1.


Now it is time to compare these two methods. I simply used STATISTICS IO and the EXECUTION TIME to get the evaluation.


Comparison

DECLARE @StartingTime datetime, @EndingTime datetime

Print ‘method1:’

SET STATISTICS IO ON
SET @StartingTime = getdate()

SELECT MIN(IDENTITYCOL) + IDENT_INCR('OrderHeader')
FROM OrderHeader t1
WHERE IDENTITYCOL BETWEEN IDENT_SEED('OrderHeader') AND 32766
    AND NOT EXISTS (SELECT * FROM OrderHeader t2
        WHERE t2.IDENTITYCOL = t1.IDENTITYCOL + IDENT_INCR('OrderHeader'))

SET @EndingTime = getdate()
SET STATISTICS IO OFF

SELECT DATEDIFF(ms, @StartingTime, @EndingTime ) AS ExecTimeInMS

Print ‘method2:’

SET STATISTICS IO ON
SET @StartingTime = getdate()

SELECT TOP 1 intNumber
FROM OrderHeader
    RIGHT OUTER JOIN tb_Numbers
    ON tb_Numbers.intNumber = OrderHeader.intID
WHERE intID IS NULL AND intNumber < = (SELECT MAX(intID) FROM OrderHeader)

SET @EndingTime = getdate()
SET STATISTICS IO OFF

SELECT DATEDIFF(ms, @StartingTime, @EndingTime ) AS ExecTimeInMS
Output:
Method1:

2210

Table 'OrderHeader'. Scan count 9998, logical reads 20086, physical reads 0, read-ahead reads 0.

ExecTimeInMS
------------
200

Method2:
2210

Table 'tb_Numbers'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 0.
Table 'OrderHeader'. Scan count 2, logical reads 14, physical reads 0, read-ahead reads 0.

ExecTimeInMS
------------
0
 

As per the output, there are 20086 logical reads and it has taken 200 ms for the first method. But in second method there are only 19 logical reads and the execution time is less considerable.

That’s why I selected to continue in my way. But there may be a side that I have not seen but you can see. So, try on this and see whether how this T-SQL solution suit for you.


I highly appreciate your comments and suggestion.

 

You can reach me through dinesh@dineshpriyankara.com .

'programming > MSSQL' 카테고리의 다른 글

Naming Standard  (3) 2003.12.09
Calling COM Objects From T-SQL  (0) 2003.12.09
TSQL 이야기 - UNION  (0) 2003.11.28

T-SQL을 이용해 COM Object를 호출하는 방법

 

자세한 내용은 Books Online을 참조하라니 --;;

혹시 쓸 일이 있을거 같아 본김에 퍼놓았습니다.

더 좋은 ref가 있으면 알려주심 ㄳ

 

출처 : http://www.sqlteam.com/item.asp?ItemID=322

 

Calling COM Objects From T-SQL
sqlguru on 9/13/2000 in Stored Procs
Dan (and Nathan, and a few others) writes: "I've heard/read that you can call a COM Object from within a stored proc. Could you explain how this is done?"

Yup. This is fairly straightforward; check it out.

The functions mentioned here are all well documented in SQL Server Books Online, so I'm not going to go into a lot of detail. If you have further questions, you know where to send them :)

Calling a COM object from T-SQL is pretty easy. First, you call sp_OACreate to create an instance of the object. This stored proc returns an integer value (a handle) that you'll need later.

Next, you call sp_OAMethod to invoke a method of the object. sp_OAGetProperty will retrieve the value of a property from the object; conversely, sp_OASetProperty will set the value of one of the object's properties.

While you're calling these stored procs to manipulate the object, you use sp_OAGetErrorInfo after each call to see if the object threw an error. Error handling for COM object calls is mostly a manual process, so be prepared to do a lot of typing :)

Once you're done using the object, you call sp_OADestroy to free the object. Objects that aren't explicitly freed are automatically freed by SQL Server at the end of the query batch.

Since COM and SQL Server data types don't match up exactly, I suggest you check out the topic titled "Data Type Conversions Using OLE Automation Stored Procedures" in Books Online.

Books Online also has a topic titled "OLE Automation Sample Script" that has a nice example of calling all of these procedures.

-SQLGuru

'programming > MSSQL' 카테고리의 다른 글

Reusing Identities  (0) 2003.12.09
TSQL 이야기 - UNION  (0) 2003.11.28
TSQL 이야기...  (0) 2003.11.28

UNION, UNION ALL

 

UNION ALL은 결과를 리턴하기 전에 중복되는 값을 제거하는 과정을 거치지 않아서, UNION보다 빠르다고 합니다.

즉 UNION 연산자는 중복된 값을 제거하고 데이터를 정렬 시킨다는 얘기가 되겠죠.

 

그러므로, 중복되는 값이 있어도 상관이 없는 경우라면 UNOIN보다는 UNOIN ALL을 사용해야 합니다.

'programming > MSSQL' 카테고리의 다른 글

Calling COM Objects From T-SQL  (0) 2003.12.09
TSQL 이야기...  (0) 2003.11.28
[컬럼]SQL Server에 별칭(Alias)을 달아보자  (2) 2003.11.13

SQL Server를 만진지 이제 언 3년 8개월...

 

아는게 별로 없는 상태로 회사에 입사해서, 정말 많은걸 배운거 같다.

SQL Server를 6.5부터 2000까지 써 오면서 책도 많이 보고, 경험도 많이 쌓았다.

 

나온지는 꽤 된 책이지만, 지금까지 보아온 책 중 정말 알차다는 느낌을 받은 책...

 

책 선전을 하는건 아니지만,

 

강력한 SQL 프로그래밍을 위한 Transact SQL

켄 핸더슨 지음

 

틈날때마나 조금씩 조금씩 읽으면서, 좋은 내용에는 줄도 그어가면서 봤는데...

좋은 내용들을 보다 많은 사람들과 공유하고 싶어서 내 블로에 조금씩 올리려고 한다.

 

제목은 'TSQL 이야기'...

 

주로 SQL에 관련된 이야기이기는 하지만 아무래도 SQL Server를 기반으로 하고 있어, 타 DBMS를 사용하는 분들께는 적용되지 않는 이야기들도 있겠지만... 봐두면 좋을만한 내용들을 뽑아 조금씩 소개하고 싶다.

 

'programming > MSSQL' 카테고리의 다른 글

TSQL 이야기 - UNION  (0) 2003.11.28
[컬럼]SQL Server에 별칭(Alias)을 달아보자  (2) 2003.11.13
복제 설정 시 자주 발생하는 에러  (4) 2003.11.13

마이크로소프트 TechNet 사이트에서 펀 글입니다.

 

---------------------------------------------------------------------------

 

김기홍 대리 / MCSE, MCDBA, 한국마이크로소프트 고객기술지원부

어느 날인가 고객으로부터 다급한 목소리로 전화가 걸려왔다.
"SQL Server에서 DTS (Data Transformation Service)를 수행하였을 때 원본 테이블 데이터가 사라졌어요"
아니 이럴 수가!! 이것이 사실이라면 정말 큰일인 것이다. RDMS 시스템에서 어떤 버그로 인해 데이터가 손실된다는 것은 상상조차 하기 힘든 일인데, 테이블내용이 통째로 사라지다니.. 일단 고객에게 100리나 되는 거리를 단숨에 달려갔다. 고객은 내 눈앞에서 실제로 원본 테이블내용이 사라지는 것을 시연해 주었다.
"A"라는 원본 SQL Server에서 "B"라는 대상 SQL Server로 테이블을 DTS하니 원본 테이블의 내용이 사라지는 것이다. (이때 DTS의 기본 설정은 대상 테이블이 존재 할 때, 대상 테이블을 제거 후 재생성 하는 옵션을 가지고 있었다.) 필자는 습관적으로 DTS를 수행한 클라이언트 장비에서 SQL Server 네트워크 유틸리티의 별칭을 조사해 보았다. 아니나 다를까 사건의 비밀은 거기에 존재하고 있었다.

고객은 자신의 장비에 "B"라는 이름을 가지고 "A"라는 서버를 연결하도록 설정한 "별칭"이 설정되어 있었다는 사실을 모르고 있었던 것이었다. 이런 황당한 사태를 유발한 "별칭"은 무엇일까? 이 별칭을 설명하기 위해서 MDAC과 SQL Server 클라이언트 네트워크 유틸리티에 대해 먼저 설명하고자 한다.

MDAC (Microsoft Data Access Component)이란?

Microsoft 관련 제품을 사용하다 보면, 간혹 MDAC이란 이름을 접하게 된다.
MDAC은 Windows NT4 Service Pack 4 또는 Internet Explorer 4.0 이후 출시된 대부분의 Microsoft 제품 (Windows, Office, Visual Studio, Internet Explorer 및 모든 서버 제품군)에 포함되어있으며, 사용자도 인지하지 못하는 사이에 (아니 자세히 관찰하면 제품설치 시 MDAC 설치 화면을 볼 수 있다.) 항상 상위 버전으로 자동 설치 될 뿐, 제거되거나 하위 버전으로 변경되는 경우는 거의 없다. 그럼 이 MDAC이란 무엇일까?
Web 또는 LAN 이용하여 데이터를 주고받는 클라이언트/서버 형태의 응용프로그램에서 관계형(SQL) 또는 비관계형에 상관없이 다양한 데이터 소스로부터 쉽게 정보(Information)을 통합-공유할 수 있는 ADO, OLE DB, ODBC 등의 컴포넌트들을 제공하여 준다.

MDAC의 버전

그 동안 배포된 MDAC의 버전을 살펴보면, MDAC 1.5, 2.0, 2.1, 2.5, 2.6, 2.7, 2.8등 다양한 버전이 존재하며, 또한 각 버전별 Service Pack도 존재한다. 이 많은 버전들의 MDAC을 설치하는 원칙은 매우 단순하다. 데이터를 공급 받는 클라이언트(데이터 소비자)의 MDAC 버전은 데이터를 제공하는 서버(데이터 소스)의 MDAC 버전보다 높거나 최소한 같아야 한다. 이렇게 하여야지만 데이터 소스에서 제공하는 모든 기능 및 기존 문제점들을 수용할 수 있게 된다. 일례로 자신의 장비에 MDAC 버전을 최소 어느 버전 이상으로 설치하여야 하는가는 자신의 장비에서 연결하는 최신 SQL Server 버전 및 서버에 설치된 최신 SQL Server Service Pack 버전이 포함한 MDAC 보다 같거나 높으면 된다. 추가로 요즈음 제공되는 MDAC관련 Tool의 경우 설치된 MDAC 버전을 제거하거나, 하위 버전으로 회귀하는 기능들을 제공하기도하지만 절대적인 원칙은 항상 MDAC은 상위 버전으로 변경될 뿐 하위버전으로 변경하는 것을 권장하지 않는다. (일부 클러스터 환경에서는 서버 환경에 특정 버전 이상의 MDAC 설치를 권장하지 않는 경우도 있지만..)

SQL Server의 제품 CD 및 SQL Server Service Pack CD를 살펴 보면 "x86\other\sqlredis.exe"라는 파일을 공통적으로 발견할 수 있다. 이 sqlredis.exe의 경우 최신 MDAC과 완전하게 동일하지는 않지만, 현재 설치된 SQL Server 버전에 문제없이 연결이 가능하도록 구성되었으며, 재배포 가능한 형태의 MDAC 대부분 컴포넌트를 포함하고, Remote에서 설치가 가능한 무인실행 설치 파일이다. 따라서 방화벽 클라이언트 응용프로그램들이 방화벽 또는 프락시 서버에서 공유되도록 하듯이, SQL Server 관리자들은 sqlredis.exe를 SQL Server 상에서 파일 공유하여 해당 SQL Server를 연결하고자 하는 모든 클라이언트는 이 파일(sqlredis.exe) 설치에 의해 SQL Server연결에 관련된 기본 요건을 쉽게 구성할 수 있도록 하는 것도 하나의 유용한 팁이 될 수 있다.

SQL Server를 사용하는 웹서버 및 기타 응용프로그램 서버 관리자의 경우, 잊지 말고 SQL Server Service Pack 적용 시 항상 각각의 웹서버에 이 sqlredis.exe를 수행하여 클라이언트의 MDAC 버전을 서버와 일치 시켜준다면, 향후 겪게 될 많은 문제점들을 피해 갈 수 있을 것이다.

SQL Server 클라이언트 네트워크 유틸리티

위에서 설명된 MDAC이 설치된 경우 여러분은 다음과 같은 방법에 의해 SQL Server 클라이언트 네트워크 유틸리티라는 것이 포함되어 있음을 확인할 수 있다.
    ->[시작] - [실행] 에서 "Cliconfg.exe" 을 입력 후 "확인"을 클릭
    ->이후 화면에 SQL Server 클라이언트 네트워크 유틸리티라는 창이 나타난다.
SQL Server 클라이언트 네트워크 유틸리티의 창 형태는 설치된 MDAC 버전에 따라 화면이 조금씩 틀린 점을 유의하여야 한다.

SQL Server 클라이언트 네트워크 유틸리티는 다음과 같은 용도에 사용하는 그래픽 기반 도구이며, 기본적으로 다음 네 가지의 탭을 가지고 있다.

  • 일반 탭: 지정된 서버에 대한 네트워크 프로토콜 연결을 만들고, 기본 네트워크 프로토콜을 변경가능.
  • 별칭 탭: 클라이언트가 연결하는 컴퓨터의 서버 별칭에 대한 정보를 나열.
  • DB 라이브러리 옵션 탭: 시스템에 현재 설치되어 있는 네트워크 라이브러리에 대한 정보를 표시.
  • 네트워크 라이브러리 옵션 탭: 시스템에 현재 설치되어 있는 DB 라이브러리 버전을 표시하고 DB 라이브러리 옵션의 기본값을 설정.
일반 탭의 경우 SQL Server 2000 출시 이전 MDAC에서는 Named Pipe가 SQL Server 연결 시 사용되는 기본 프로토콜 이었으나, SQL Server 2000 출시 이후 MDAC에서는 TCP/IP 가 기본 프로토콜임을 확인할 수 있다.


별칭(Alias)이란?

SQL Server 클라이언트 네트워크 유틸리티에서 재미있고, 독특한 동작방식을 가지는 것이 별칭 탭에서 설정 가능한 SQL Server 별칭이다.
SQL Server 별칭의 경우 각 SQL Server 별로 사용하는 네트워크 라이브러리 (Named Pipe, TCP/IP, Multiprotocol등)를 지정할 수 있고, 또한 사용하고자 하는 매개변수 (Named Pipe의 파이프 이름, TCP/IP의 Port 번호 등)를 지정이 가능하다. 일반적으로 별칭사용을 많이 접하는 사례는 보안 이슈에 의해 SQL Server를 1433이 아닌 다른 고정 포트로 서비스하는 경우 SQL Server의 클라이언트 (웹서버 및 데스크탑 PC등)들에게 특정 SQL Server의 TCP/IP Port를 지정하는 것은 종종 볼 수 있다. 그러나 이 별칭의 기능이 단순히 이것만 있는 것일까? 활용하기에 따라 처음에 DTS 사례에서 언급했던 것 같은 흥미로운 결과를 초래하는 경우가 많다.

별칭의 동작 방식

별칭은 각 클라이언트 별로 자신에게 설정된 사항만 적용된다.
만약 "Server1"와 "Server2"라는 SQL Server가 존재하고 "Client1"와 "Client2"라는 클라이언트 장비가 존재 할 때 "Client1"에만 서버 별칭이름을 "Server2" 그리고 서버 이름을 "Server1"로 지정 추가한 경우에, 각각의 "Client1"과 "Client2"에서 "Server1"과 "Server2"를 연결하면 어떤 서버가 연결될까? 당연히 "Client2"에서는 "Server1"과 "Server2"가 정상적으로 연결 가능. 하지만 "Client1"에서 "Server1"을 연결하는 경우에는 "Server1"이 연결되고, 별칭 사용에 의해 "Server2"를 연결한 경우 "Server1"로 연결된다. 이 때 "Client1"에서 SQL Server 명을 별도로 확인하지 않으면 자신은 "Server1"에 연결된 상태로 착각할 수 있다.

만약 세 사람이 구름 한 점 없는 푸른 하늘을 쳐다 보고 있다. 이 때 한 사람은 짙은 빨간색 색안경을, 또 한 사람은 짙은 노란색 색안경을, 그리고 나머지 한 사람은 전혀 색안경을 끼지 않은 경우 이 세 사람이 보고 있는 하늘의 색채는 푸른 빛, 붉은 빛, 노란 빛으로 보일 수 있다. 별칭 또한 마찬 가지로 푸른색(Server1)붉은색(Server2)으로 보이게 할 수 있는 색안경과 같은 역할을 한다. 하지만 각기 자기가 착용한 색안경에만 영향을 받을 뿐 다른 사람이 착용한 색안경에는 전혀 영향을 받지 않는다. 그러나 상당히 위험할 수 있는 경우는 처음에 언급된 DTS 사례처럼 자신이 색안경을 착용한지를 모르는 경우 뜻하지 않은 사태가 발생할 수 있음도 유의 하여야 한다.

별칭의 적용 사례

  1. 4대의 웹서버가 SQL Server를 사용하고 있는데 운영중인 SQL Server ("ServerA")의 장애 발생시 Standby SQL Server("ServerB")로 1~2분 내로 연결을 변경하고 싶은데 어떻게 해야 하나요? (이 때 Standby Server는 Log Shipping에 의해 운영 데이터와 15분의 차이는 있지만 ReadOnly 상태로 임시적 운영예정이어서 데이터 동기화는 큰 문제가 없습니다만 IP와 서버명을 변경하여 System을 Restart하기에는 시간이 너무 촉박합니다.)
    : 답은 간단하다. 각 웹서버에 서버 별칭은 "ServerA"로 서버 이름은 "ServerB"로 설정된 별칭을 추가하면, 별칭이 추가된 순간부터 연결되는 SQL Server Connection은 ServerB로 연결된다.
  2. 하나의 Domain을 사용하는 3000대 PC에서 SQL Server를 직접 연결하는데, SQL Server명과 IP, Port 가 모두 바뀌어야 하는 불가피한 상황이 발생 했습니다. 그런데 응용프로그램의 SQL Server 정보를 변경하여 새로 배포하지 않고, 모든 PC에서 기존의 SQL Server가 아닌 새로 변경된 SQL Server명과 IP, Port를 연결할 수 있는 방법이 없을까요?
    : 마찬가지로 방법이 그리 어려운 것은 아니다. Domain LogOn시 다음 registry를 항목을 추가하는 Domain LogOn Script를 설정 하거나, .reg 파일을 배포 및 실행하면 된다. Ex) TCP/IP Connection 사용
    -> Old SQL Server 서버명 : OLDSERVER ; IP : 10.10.10.1 ; Port : 1433
    -> New SQL Server 서버명 : NEWSERVER ; IP : 10.10.10.2 ; Port : 1064

    ----------------------------------
    Windows Registry Editor Version 5.00

    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo]
    "OLDSERVER"="DBMSSOCN,NEWSERVER,1064"
    "10.10.10.1 "="DBMSSOCN, 10.10.10.2,1064"

    추가 사항:
    - MDAC 2.6 이상에서 Dynamic Port를 사용하고 싶은 경우 예제
    "OLDSERVER "="DBMSSOCN, NEWSERVER"

    - Named Pipe를 사용하는 경우 예제
    "OLDSERVER"="DBNMPNTW,\\\\NEWSERVER\\pipe\\sql\\query"

    - Multiprotocol을 사용하는 경우 예제
    "OLDSERVER "="DBMSRPCN,NEWSERVER"

참고로 SQL Server의 대다수 사용자들이 가장 많이 겪는 문제점들이 SQL Server의 연결과 관련된 문제이므로 아래 첨부된 웹캐스트를 활용하면 많은 도움이 될 것이다.
Support WebCast: Microsoft SQL Server 2000: Troubleshooting Connectivity  

SQL Server 2000이 출시된 이후 SQL Server 연결 시 SQL Server Name에 대한 Name Resolution이 필수적인 경우가 많아 연결 문제가 더 잦아지는 경향도 없지 않다. 이때 네트워크 구성에 따라 Hosts 또는 lmhosts 파일에 SQL Server Name을 수동 추가하는 작업으로 인해 상당수의 SQL Server 연결 문제를 해결하는 경우가 상당수 있다.

이상으로 MDAC, SQL Server 클라이언트 네트워크 유틸리티, 별칭 등에 대해 간략하게 살펴 보았다. 만약 지금까지의 내용을 개개인의 PC상에서 점검해 보면 이미 상당수의 사용자들이 SQL Server 연결과 관계된 많은 설정 및 콤포넌트들을 본인들도 인지하지 못하는 사이에 사용하고 있었음을 발견할 수 있을 것이다.

 

출처 : http://www.microsoft.com/korea/technet/resources/Technetcolumn/column_12.asp

 

'programming > MSSQL' 카테고리의 다른 글

TSQL 이야기...  (0) 2003.11.28
복제 설정 시 자주 발생하는 에러  (4) 2003.11.13
[Tip]mdf파일 만으로 DB 복구하는 방법  (0) 2003.11.12

에러 메세지

'SQL Server 엔터프라이즈 관리자이(가) XXX을(를) XXX의 배포자로 구성할 수 없습니다.

 

오류 18483: 'distributor_admin'이(가) 서버에서 원격 로그인으로 정의되어 있지 않기 때문에 XXX서버에 연결할 수 없습니다.'

라는 에러 발생시 점검해야 할 것.

- SELECT @@servername 을 통해 실제 서버이름과 일치하는지를 확인. 일치하지 않는 경우 'sp_dropserver'를 통해 서버를 drop하고 'sp_addserver 서버이름, 'local''을 이용해 서버 이름을 새로 등록한 후 서비스를 재 시작하고 다시 SELECT @@servername을 해 보면 바뀐 이름을 확인해 볼 수 있다.

- 엔터프라이즈 메니저에 서버를 등록할 때, 꼭 서버 이름으로 등록할 것 ('local'이나 ip혹은 .으로 등록하지 말것)

 

 

EXEC sp_attach_single_file_db 'pubs' , 'c:\Program Files\Microsoft SQL Server\MSSQL\Data\pubs.mdf' 

'programming > MSSQL' 카테고리의 다른 글

복제 설정 시 자주 발생하는 에러  (4) 2003.11.13
인덱스 고르는 방법  (0) 2003.10.16
[튜닝] index...  (0) 2003.10.14

대부분 다 아시는 내용이겠지만, 이제막 c#을 공부하는 나로써 필요한 것들 ^^;;

 

다차원 배열 생성 시 각 차원의 길이를 알아내는 방법

int [,]a = {.............};

a.getLength(0);  -> 1차원의 길이

a.getLength(1);  -> 2차원의 길이

 

 

'programming > c#' 카테고리의 다른 글

정규식 ( regular expression)  (3) 2004.01.26
엑셀 파일에서 데이터를 load할 때...  (0) 2003.10.30
엑셀 파일 생성 코드  (0) 2003.10.30

데브피아 게시물에서 본건데...

oRange.Cells.Value2().toString();

을 이용할 경우 엑셀의 date형식은 TimeSpan의 숫자 값으로만 가져 오도록 되기 때문에,

엑셀에 보이는 형태로 값을 가져오려면, 아래와 같이 하면 된다.

oRange.Cells.get_Value(Missing.Value).toString();


 

'programming > c#' 카테고리의 다른 글

배열관련 사항  (2) 2003.10.30
엑셀 파일 생성 코드  (0) 2003.10.30
프로젝트 배포  (0) 2003.10.20
마이크로소프트 기술자료 - Q302084

HOWTO: Automate Microsoft Excel from Microsoft Visual C# .NET

The information in this article applies to:
Microsoft Visual C# .NET (2002)
Microsoft Excel 2000
Microsoft Excel 2002

SUMMARY
This article demonstrates how to create an Automation client for Excel by using Visual C# .NET. 
MORE INFORMATION
Automation is a process that permits applications that are written in languages such as Visual C# .NET to programmatically control other applications. Automation to Excel permits you to perform actions such as creating a new workbook, adding data to the workbook, or creating charts. With Excel and other Microsoft Office applications, virtually all of the actions that you can perform manually through the user interface can also be performed programmatically by using Automation.

Excel exposes this programmatic functionality through an object model. The object model is a collection of classes and methods that serve as counterparts to the logical components of Excel. For example, there is an Application object, a Workbook object, and a Worksheet object, each of which contain the functionality of those pieces of Excel. To access the object model from Visual C# .NET, you can set a project reference to the type library.

This article demonstrates how to set the proper project reference to the Excel type library for Visual C# .NET and provides sample code to automate Excel. 
Create an Automation Client for Microsoft Excel
Start Microsoft Visual Studio .NET. On the File menu, click New and then click Project. Select Windows Application from the Visual C# Projects types. Form1 is created by default.
Add a reference to the Microsoft Excel Object Library. To do this, follow these steps:
On the Project menu, click Add Reference.
On the COM tab, locate Microsoft Excel Object Library and click Select. 

NOTE: The Excel Object Library contains a version number; the version for Microsoft Excel 2000 is 9.0 and the version for Microsoft Excel 2002 is 10.0.
Click OK in the Add References dialog box to accept your selections. If you receive a prompt to generate wrappers for the libraries you selected, click Yes.
On the View menu, select Toolbox to display the Toolbox and add a button to Form1.
Double-click Button1. The code window for the form appears.
In the code window, replace the following code
private void button1_Click(object sender, System.EventArgs e)
{
}
with: 
private void button1_Click(object sender, System.EventArgs e)
{
    Excel.Application oXL;
    Excel._Workbook oWB;
    Excel._Worksheet oSheet;
    Excel.Range oRng;

    try
    {
        //Start Excel and get Application object.
        oXL = new Excel.Application();
        oXL.Visible = true;

        //Get a new workbook.
        oWB = (Excel._Workbook)(oXL.Workbooks.Add( Missing.Value ));
        oSheet = (Excel._Worksheet)oWB.ActiveSheet;

        //Add table headers going cell by cell.
        oSheet.Cells[1, 1] = "First Name";
        oSheet.Cells[1, 2] = "Last Name";
        oSheet.Cells[1, 3] = "Full Name";
        oSheet.Cells[1, 4] = "Salary";

        //Format A1:D1 as bold, vertical alignment = center.
        oSheet.get_Range("A1", "D1").Font.Bold = true;
        oSheet.get_Range("A1", "D1").VerticalAlignment = 
            Excel.XlVAlign.xlVAlignCenter;
        
        // Create an array to multiple values at once.
        string[,] saNames = new string[5,2];
        
        saNames[ 0, 0] = "John";
        saNames[ 0, 1] = "Smith";
        saNames[ 1, 0] = "Tom";
        saNames[ 1, 1] = "Brown";
        saNames[ 2, 0] = "Sue";
        saNames[ 2, 1] = "Thomas";
        saNames[ 3, 0] = "Jane";
        saNames[ 3, 1] = "Jones";
        saNames[ 4, 0] = "Adam";
        saNames[ 4, 1] = "Johnson";

        //Fill A2:B6 with an array of values (First and Last Names).
        //EXCEL9 use:
        oSheet.get_Range("A2", "B6").Value2 = saNames;
        //EXCEL10 use:
        //oSheet.get_Range("A2", "B6").set_Value( Missing.Value, saNames );

        //Fill C2:C6 with a relative formula (=A2 & " " & B2).
        oRng = oSheet.get_Range("C2", "C6");
        oRng.Formula = "=A2 & \" \" & B2";

        //Fill D2:D6 with a formula(=RAND()*100000) and apply format.
        oRng = oSheet.get_Range("D2", "D6");
        oRng.Formula = "=RAND()*100000";
        oRng.NumberFormat = "$0.00";

        //AutoFit columns A:D.
        oRng = oSheet.get_Range("A1", "D1");
        oRng.EntireColumn.AutoFit();

        //Manipulate a variable number of columns for Quarterly Sales Data.
        DisplayQuarterlySales(oSheet);

        //Make sure Excel is visible and give the user control
        //of Microsoft Excel's lifetime.
        oXL.Visible = true;
        oXL.UserControl = true;
    }
    catch( Exception theException ) 
    {
        String errorMessage;
        errorMessage = "Error: ";
        errorMessage = String.Concat( errorMessage, theException.Message );
        errorMessage = String.Concat( errorMessage, " Line: " );
        errorMessage = String.Concat( errorMessage, theException.Source );

        MessageBox.Show( errorMessage, "Error" );
    }
}

private void DisplayQuarterlySales(Excel._Worksheet oWS)
{
    Excel._Workbook oWB;
    Excel.Series oSeries;
    Excel.Range oResizeRange;
    Excel._Chart oChart;
    String sMsg;
    int iNumQtrs;

    //Determine how many quarters to display data for.
    for( iNumQtrs = 4; iNumQtrs >= 2; iNumQtrs--)
    {
        sMsg = "Enter sales data for ";
        sMsg = String.Concat( sMsg, iNumQtrs );
        sMsg = String.Concat( sMsg, " quarter(s)?");

        DialogResult iRet = MessageBox.Show( sMsg, "Quarterly Sales?", 
            MessageBoxButtons.YesNo );
        if (iRet == DialogResult.Yes)
            break;
    }

    sMsg = "Displaying data for ";
    sMsg = String.Concat( sMsg, iNumQtrs );
    sMsg = String.Concat( sMsg, " quarter(s)." );
    MessageBox.Show( sMsg, "Quarterly Sales" );

    //Starting at E1, fill headers for the number of columns selected.
    oResizeRange = oWS.get_Range("E1", "E1").get_Resize( Missing.Value, iNumQtrs);
    oResizeRange.Formula = "=\"Q\" & COLUMN()-4 & CHAR(10) & \"Sales\"";

    //Change the Orientation and WrapText properties for the headers.
    oResizeRange.Orientation = 38;
    oResizeRange.WrapText = true;

    //Fill the interior color of the headers.
    oResizeRange.Interior.ColorIndex = 36;

    //Fill the columns with a formula and apply a number format.
    oResizeRange = oWS.get_Range("E2", "E6").get_Resize( Missing.Value, iNumQtrs);
    oResizeRange.Formula = "=RAND()*100";
    oResizeRange.NumberFormat = "$0.00";

    //Apply borders to the Sales data and headers.
    oResizeRange = oWS.get_Range("E1", "E6").get_Resize( Missing.Value, iNumQtrs);
    oResizeRange.Borders.Weight = Excel.XlBorderWeight.xlThin;

    //Add a Totals formula for the sales data and apply a border.
    oResizeRange = oWS.get_Range("E8", "E8").get_Resize( Missing.Value, iNumQtrs);
    oResizeRange.Formula = "=SUM(E2:E6)";
    oResizeRange.Borders.get_Item( Excel.XlBordersIndex.xlEdgeBottom ).LineStyle 
        = Excel.XlLineStyle.xlDouble;
    oResizeRange.Borders.get_Item( Excel.XlBordersIndex.xlEdgeBottom ).Weight 
        = Excel.XlBorderWeight.xlThick;

    //Add a Chart for the selected data.
    oWB = (Excel._Workbook)oWS.Parent;
    oChart = (Excel._Chart)oWB.Charts.Add( Missing.Value, Missing.Value, 
        Missing.Value, Missing.Value );

    //Use the ChartWizard to create a new chart from the selected data.
    oResizeRange = oWS.get_Range("E2:E6", Missing.Value ).get_Resize( 
        Missing.Value, iNumQtrs);
    oChart.ChartWizard( oResizeRange, Excel.XlChartType.xl3DColumn, Missing.Value,
        Excel.XlRowCol.xlColumns, Missing.Value, Missing.Value, Missing.Value, 
        Missing.Value, Missing.Value, Missing.Value, Missing.Value );
    oSeries = (Excel.Series)oChart.SeriesCollection(1);
    oSeries.XValues = oWS.get_Range("A2", "A6");
    for( int iRet = 1; iRet <= iNumQtrs; iRet++)
    {
        oSeries = (Excel.Series)oChart.SeriesCollection(iRet);
        String seriesName;
        seriesName = "=\"Q";
        seriesName = String.Concat( seriesName, iRet );
        seriesName = String.Concat( seriesName, "\"" );
        oSeries.Name = seriesName;
    }                                                          
    
    oChart.Location( Excel.XlChartLocation.xlLocationAsObject, oWS.Name );

    //Move the chart so as not to cover your data.
    oResizeRange = (Excel.Range)oWS.Rows.get_Item(10, Missing.Value );
    oWS.Shapes.Item("Chart 1").Top = (float)(double)oResizeRange.Top;
    oResizeRange = (Excel.Range)oWS.Columns.get_Item(2, Missing.Value );
    oWS.Shapes.Item("Chart 1").Left = (float)(double)oResizeRange.Left;
}
NOTE: As written, this code uses the Excel 9.0 object library. When you added references to your project, if you selected the Excel 10.0 object library instead of the Excel 9.0 object library, search the code for comments that contain "//EXCEL10" and uncomment the line(s) of code to which the comment refers. Likewise, search the code for comments that contain "//EXCEL9" and comment the line(s) of code to which the comment refers.


Scroll to the top of the code window. Add the following line to the end of the list of using directives:
using System.Reflection;
Test the Automation Client
Press F5 to build and run the program.
Click Button1 on the form. The program starts Excel and populates data on a new worksheet.
When you are prompted to enter quarterly sales data, click Yes. A chart that is linked to quarterly data is added to the worksheet.

(c) Microsoft Corporation 2001, All Rights Reserved. Contributions by Joel Alley, Microsoft Corporation.

'programming > c#' 카테고리의 다른 글

엑셀 파일에서 데이터를 load할 때...  (0) 2003.10.30
프로젝트 배포  (0) 2003.10.20
Excel 파일 읽어오는 방법  (0) 2003.10.20

Deploying Applications

The .NET Framework provides a number of basic features that make it easier to deploy a variety of applications. This section briefly describes those features and provides information about packaging and distributing applications with the .NET Framework.

In This Section

.NET Framework Deployment Features
Provides a brief overview of the deployment features in the .NET Framework
.NET Framework Deployment Basics
Provides an overview of packaging and distributing .NET Framework applications.
Deployment Scenarios
Describes several possible deployment scenarios for .NET Framework applications.
How the Runtime Locates Assemblies
Describes how the common language runtime determines which assembly to use to fulfill a binding request.
Redistributing the .NET Framework
Describes where to obtain the .NET Framework redistributable package, Dotnetfx.exe, and how to use it to deploy the .NET Framework on user and server computers.

Related Sections

Deploying XML Web Services
Describes how to deploy an XML Web service.
Packaging and Deploying Resources
Describes how to package and deploy resources.
Deploying an Interop Application
Describes how to deploy an interop application.
Developing a Simple Windows Forms Control
Describes key steps for authoring a custom Windows Forms control.
Developing a Simple ASP.NET Server Control
Describes key steps for authoring a custom server control.
Deploying an Application for COM Access
Describes how to deploy applications for use by COM clients.

'programming > c#' 카테고리의 다른 글

엑셀 파일에서 데이터를 load할 때...  (0) 2003.10.30
엑셀 파일 생성 코드  (0) 2003.10.30
Excel 파일 읽어오는 방법  (0) 2003.10.20

참조 : http://www.c-sharpcorner.com

 

How to Open and Read an Excel Spreadsheet into a ListView in .NET

Submitted ByUser LevelDate of Submission
Michael GoldIntermediate11/26/2001


Figure 1 - Excel Spreadsheet read into a ListView

    Source Code:  ExcelReadMG.zip

The Interoperability services make it very easy to work with COM Capable Applications such as Word and Excel.  You can also refer to my previous article on the topic: Real-time Stock Quotes in Excel using .NET for more information on accessing Excel via .NET.  This article was written in response to a question asking How do I open and excel file and read it using .NET? 

The first step is to create a reference in your project to Excel 9.0 Objects Library.  This is done by right mouse clicking on the References folder in the Solution Explorer and choosing Add Reference. This brings up the Tab Dialog below.  Choose the COM Tab and pick Microsoft Excel 9.0 Objects Library.

Figure 2 - Adding an Excel Reference

This action puts an Interop.Excel.dll and Interop.Office.dll into your bin directory so you can manipulate excel.  

Now we can declare our Excel Application Object and the compiler will recognize it:

private Excel.Application ExcelObj = null;

Excel is launched and an Application reference is obtained in the constructor of our form.  First an Excel Application object is constructed.  Then we check to make sure Excel was actually started. If it was, we have a valid application object and we can now use it to open a file:

public Form1()
{

// Initialize the Windows Components

InitializeComponent();

ExcelObj = new Excel.Application();

//  See if the Excel Application Object was successfully constructed
if (ExcelObj == null)
 {
  MessageBox.Show("ERROR: EXCEL couldn't be started!");
  System.Windows.Forms.Application.Exit();
 }

//  Make the Application Visible

  ExcelObj.Visible = true;

}

The code for opening the Excel file is shown below.  The code uses the OpenFileDialog component to get the path name for the Excel file.  The Excel file is opened using the WorkBooks collections' Open method.  This method takes 15 parameters with the following definition.  

Function Open(Filename As String, [UpdateLinks], [ReadOnly], [Format], [Password], [WriteResPassword], [IgnoreReadOnlyRecommended], [Origin], [Delimiter], [Editable], [Notify], [Converter], [AddToMenuRecentlyUsed]) As Workbook

We really are only interested in the FileName, but have added the other default parameters for your reference.  There is also an OpenText method in Workbooks for opening tab or comma delimited text files.

private void menuItem2_Click(object sender, System.EventArgs e)
{

 // prepare open file dialog to only search for excel files (had trouble setting this in design view)
  this.openFileDialog1.FileName = "*.xls";
  if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
   {

  // ***********  Here is the call to Open a Workbook in Excel ****************
  // It uses most of the default values (except for the read-only which we set to true)
    Excel.Workbook theWorkbook = ExcelObj.Workbooks.Open(
          openFileDialog1.FileName, 0, true, 5,
          "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false,
          0, true);

    // get the collection of sheets in the workbook
    Excel.Sheets sheets = theWorkbook.Worksheets;

   // get the first and only worksheet from the collection
   // of worksheets

    Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1);

   // loop through 10 rows of the spreadsheet and place each row in the list view
   for
(int i = 1; i <= 10; i++)
    {
     Excel.Range range = worksheet.get_Range("A"+i.ToString(), "J" + i.ToString());
     System.Array myvalues = (System.Array)range.Cells.Value;
     string[] strArray = ConvertToStringArray(myvalues);
     listView1.Items.Add(new ListViewItem(strArray));
   }

  }

}

You also may want to note the ConvertToStringArray method which is used to convert a System.Array into a string array.  If someone knows an easier way to do this, please let me know and I'll alter the article.  The problem is that an Excel Array comes back as two dimensional even if you are selecting a range of a single row, so you need to change the 2-d array into something the listview can accept. Also the listview array is 0 based and the Excel range array is 1 based.

string[] ConvertToStringArray(System.Array values)
{

// create a new string array
string
[] theArray = new string[values.Length];

// loop through the 2-D System.Array and populate the 1-D String Array
 for (int i = 1; i <= values.Length; i++)
  {
   if (values.GetValue(1, i) == null)
    theArray[i-1] = "";
  else
   theArray[i-1] = (string)values.GetValue(1, i).ToString();
  }

  return theArray;
}

That's all there is to it!  Now you can read in all your old Excel Databases.  Perhaps you can even use ADO.NET to place them into a database! (Could be the topic for the next article.  ;-)

'programming > c#' 카테고리의 다른 글

엑셀 파일에서 데이터를 load할 때...  (0) 2003.10.30
엑셀 파일 생성 코드  (0) 2003.10.30
프로젝트 배포  (0) 2003.10.20

이번에는 인덱스를 고르는 방법에 대한 글 입니다.

저도 아직 다 안 읽어봤는데... 역시 시간과 능력 되는 만큼만 번역해 놓겠습니다.

 

 

How to Select Indexes for
Your SQL Server Tables


by Manish Rawat

 

Indexing is one of the most crucial elements in increasing the performance of SQL Server. A well-written query will not show its effectiveness unless powered by an appropriate index or indexes on the table(s) used in a query, especially if the tables are large.

 

Indexes exist to make data selection faster, so the focus of this article is on ways you can select the best indexes for faster data retrieval. This is done in a two-step process.

(인덱스는 데이터의 검색을 빠르게 한다. 그래서, 이 글에선 빠른 데이터 검색을 위한 가장 좋은 인덱스를 선택하는 방법에 촛점을 맞춘다. 이것은 두 단계로 이루어진다.)

  • Step One: Gathering Information
    (첫번째 단계 : 정보 수집)
  • Step Two: Taking Actions on the Information Gathered 
  • (두번째 단계 : 수집된 정보를 바탕으로 작업 수행)

 

Indexing can be quite a challenging task if you are not familiar with your databases, the relationships between tables, and how queries are written in stored procedures and embedded SQL. How many companies you have worked for have a proper ERD diagram of their databases and have followed the textbook method style of programming? In the real world, time is often limited, resulting in poor SQL Server database performance.

If you have been tasked with optimizing a database's performance (at least to a respectable level), or you want to be proactive with your databases to prevent potential future performance issues, following these steps should help you in tuning tables, just as they have helped me. These steps are applicable at any stage of project, even if a deadline is just around the corner.

 

Step One (Gathering Information)

Interact with the people who know about the database and its table structures.

(데이터베이스와 그 데이터베이스의 테이블 구조에 대해 아는 사람들과 대화를 나눈다.)

If you know it already, that’s great. This is very important and makes your life easier.

(만약 이미 알고 있다면 좋은 일이다. 이것은 매우 중요하며, 작업을 쉽게 만들어 준다.)

 

1) Identify key tables, based on: (아래의 내용을 기반으로 KEY 테이블을 찾는다.)

  • Static tables (often called master tables).
    (정적 테이블 - 마스터 테이블이라 불린다.)
  • Highly transactional tables.
    (많은 트랜잭션이 발생하는 테이블)
  • Tables used within a lot of stored procedures or embedded SQL.
    (임베디드 SQL이나 저장프로시저에서 많이 사용된 테이블)
  • Tables with an index size greater then its data's size. You can use sp_spaceused with the table name to find table space usage.
    (데이터 크기보다 큰 사이트의 인덱스를 갖는 테이블. 'sp_spaceused'를 이용해서 찾을 수 있다.)
  • Top 10 or 15 big size tables. See a prior year database if available or applicable. The idea is to identify the largest tables in the database after it is in production. There is a script available at http://www.sqlteam.com/item.asp?ItemID=282 that you may find useful.
  • (전체 테이블 중 10~15위권 안의 사이즈가 큰 테이블.)

2) Identify the most frequently called stored procedures/queries and list all of the tables used by them.

(가장 자주 사용되는 저장 프로시저나 쿼리들을 찾아내고, 이 저장 프로시저나 쿼리에서 사용되는 테이블을 목록화한다.)

 

3) Get the SQL Profiler trace of :

  • Production site (if available/applicable). Running a trace on the production box during typical activity is worth the effort and will be fruitful in later analysis.

  • Testing site (if one is available/applicable).

  • Otherwise, get if from your development server.

It is advisable to write down information you collect in a document for later retrieval.

 

4) Before we dive into analyzing the information gathered, here are few things to keep in mind while tuning your tables:

  • To see the Query/Execution plans of queries, highlight them in SQL Query Analyzer (isqlw.exe) and select Display Estimated Query Plan (Cntl+L) from the Query menu. If you want to see the query plan of a stored procedure, select Show Execution Plan (Cntl+k) and execute the stored procedure. Also, turn on the “Set Statistics IO on “ command. Examining Query/Execution plans can be a bit time consuming. But you will find it easier if you really understand the database and its tables before you begin.

  • You need to have a good foundation on how clustered and non-clustered indexes work. See this URL for a good foundation on this topic: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/architec/8_ar_da2_8sit.asp

 

Preferred SQL Server Index Types

When you use Query Analyzer to produce a graphical execution plan, you will notice that there are several different ways SQL Server uses indexes.

1) Clustered Index Seek: A Clustered Index Seek uses the seeking ability of indexes to retrieve rows directly from a clustered index. In most cases, they provide the best performance on SELECT statements.

In Query Analyzer, go to pubs database. Type following query:

SELECT * FROM authors WHERE au_id LIKE'2%'

Highlight the query and press. (Cntl + L) or highlight the query and press F5. You will see the following in the “Estimated Execution Plan” tab.

Take a close look at the Argument section of the above illustration. Notice that the “UPKCL_auidind” clustered index is used to retrieve the data.

2) Index Seek: An Index Seek uses a non-clustered index to retrieve data, and in some ways, acts like a clustered index. This is because all of the data retrieved is fetched from the leaf layer of the non-clustered index, not from any of the data pages. You often see this behavior in a covering index.

In Query Analyzer, go to pubs database and type following query:

SELECT title_id, title FROM titles WHERE title LIKE 't%'

Highlight the query and press. (Cntl + L) or highlight the query and press F5. You will see the following in the “Estimated Execution Plan” tab:

In the Argument section in the above illustration, note that the “titleind” non-clustered index is used to retrieve the data.

3) Bookmark Lookup: A Bookmark Lookup uses a non-clustered index to select the data. It starts with an index seek in the leaf nodes of the non-clustered index to identify the location of the data from the data pages, then it retrieves the necessary data directly from the data pages. Leaf nodes of non-clustered indexes contain row locator that point to the actual data on data pages.

In Query Analyzer, go to the pubs database. Type following query:

SELECT * FROM titles WHERE title LIKE 't%'

Highlight the query and press. (Cntl + L) or highlight the query and press F5. You will see the following in the “Estimated Execution Plan” tab.

In the Argument section of the Index Seek, notice that the "titlecind" non-clustered index is used, but once the data pages are identified from looking them up in the leaf pages of the non-clustered index, then a Bookmark Lookup must be performed. Again, a Bookmark Lookup is when the Query Optimizer has to lookup the data from the data pages in order to retrieve it. In the Argument section of the Bookmark Lookup, note that a Bookmark Lookup called "Bmk1000" is used. This name is assigned automatically by the Query Optimizer.

4) Scans: Scans (Table scans, Index scan, and Clustered Index scans) are usually bad unless the table has very few rows and the Query Optimizer determines that a table scan will outperform the use of an available index. Watch out for scans in your execution plans.

In Query Analyzer, go to pubs database and type the following query:

SELECT * FROM employee WHERE hire_date > '1992-08-01'

Highlight the query and press. (Cntl + L) or highlight the query and press F5. You will see the following in the “Estimated Execution Plan” tab:

Notice that in this case, a Clustered Index Scan was performed, which means that every row in the clustered index had to be examined to fulfill the requirements of the query.

Now that we understand some of the basics of how to read Query Execution Plans, lets take a look at some additional information that you will find useful when analyzing queries for proper index use:

  • If you create multiple query or a stored procedure execution plans at the same time in Query Analyzer, you can compare the cost of each query or stored procedure to see which is more efficient. This is useful for comparing different versions of the same query or stored procedure.
    (쿼리분석기에서 다수의 쿼리나 저장프로시저에 대한 실행계획을 동시에 보면, 각각의 쿼리나 저장 프로시저의 비용을 보다 효과적으로 비교해 불 수 있다. 이런 방법은 같은 쿼리나 저장 프로시저의 다른 버젼들 간의 비교에 보다 유용하게 활용할 수 있다.)

 

  • Primary Key constraints create clustered indexes automatically if no clustered index already exists on the table and a non-clustered index is not specified when you create the PRIMARY KEY constraint.
    (기본키 제약조건은 테이블에 클러스터드 인덱스가 존재하지 않는 경우 클러스터드 인덱스를 자동적으로 생성한다.(역자주-7.0의 경우 넌클러스터드 인덱스였다. 2000이 되면서 바뀐 부분) 그리고 기본키 제약조건을 만들 때 넌클러스터드인덱스는 만들어지지 않는다.)
  • Non-clustered indexes store clustered index keys as their row locators. This overhead can be used as a benefit by creating a covering index (explained later). Using covering indexes requires caution.

  • A table's size comprises both the table’s data and the size of any indexes on that table.

  • Adding too many indexes on a table increases the total index size of atable and can often degrade performance.

  • Always add a clustered index to every table, unless there is a valid reason not to, like the table has few rows.

  • Seeks shown in Query/Execution plans for SELECT statements are good for performance, while scans should be avoided.

  • A table's size (number of rows) is also a major factor used up by Query Optimizer when determining best query plan.

  • Index order plays an important role in many query plans. For example, in the authors table of the pubs database, a non-clustered index is defined in the order of au_lname, then au_fname.


    Fine Query A

    SELECT * FROM authors WHERE au_lname like 'r%'

    This uses a Bookmark Lookup and an Index seek.

     

    Fine Query B

    select * FROM authors WHERE au_lname LIKE 'r%' AND au_fname like ‘a’

    This uses a Bookmark Lookup and an Index Seek.

     

    Not so Fine Query C

    SELECT * FROM authors WHERE au_fname LIKE ‘a’

    This uses a Clustered Index Scan.

  • SQL Server 2000 (not earlier versions) offers both ascending and descending sort orders to be specified in an index. This can be useful for queries, which uses the ORDER BY DESC clause.

  • To find a particular word (for e.g. a table name) used in all stored procedure code, you can use the following code to identify it. For example, you can use this to find out a list of SP’s using a table.

    SELECT DISTINCT a.name AS SPName FROM syscomments b, sysobjects a

    WHERE b.text LIKE '%authors%' AND a.id=b.id AND a.type='P'

This query brings all SP’s having text “authors” in their code. Note that this query might bring extra SP’s, for example, if a stored procedure uses text in a comment.

 

Step Two: What to Do Once You Have Gathered the Necessary Information

Actions for Key Tables

For static tables (tables that rarely, if ever change), you can be liberal on the number of indexes that can be added. As mentioned earlier, too many indexes can degrade the performance of highly transactional tables, but this does not apply to tables whose data will not change. The only consideration possible could be disk space. Set all index fill factors on static tables to 100 in order to minimize disk I/O for even better performance.

For highly transactional tables, try to limit the number of indexes. Always keep in mind that a non-clustered index contains the clustered index key. Because of this, limit the number of columns on your clustered index in order to keep their size small. Any index for busy transactional tables has to be highly justifiable. Choose the fill factor with caution (usually 80 to 90%) for these indexes in order to avoid potential page splitting.

For tables used lot in stored procedures/embedded SQL, these tables play an important role in the total application lifetime as they are called most often. So they require special attention. What is important is look at how tables are being accessed in queries in order to eliminate scans and convert them into seeks. Watch the logical I/O used by "Set Statistics IO on" to help you determine which queries are accessing the most data. Less logical I/O is better than more. Choose clustered index with caution. Depending on how transactional the table is, choose a higher fill factor.

For tables with index size greater then data size implies a lot of indexes, so review indexes and make sure their existence is useful and justified.

For the Top 10 or 15 largest tables, keep this fact in mind when creating indexes for these types of tables, as their indexes will also be large. Also check to see if the tables are static or non-static, which is helpful information when deciding what columns need to be indexed.

For the most frequently called Stored procedures/Embedded SQL, See the Query plans and Logical I/O page use.

SQL Profiler Trace is a very good tool. It tracks calls getting executed in SQL Server at any given point of time, their execution time, I/O reads, user logins, executing SQL statement, etc. It can also be used as debugging tool. An analysis of a Profiler trace is important to identify slow running queries. You can set the duration to > 100ms to see queries which take more then 100 milliseconds to execute.

 

Using a Covering Index + Non-clustered Index Uses Clustered Index as a Row Locator

One can leverage the fact that non-clustered indexes store clustered index keys as their row locators. Meaning that a non-clustered index can behave as a clustered index if the index has all of the columns referenced in SELECT list, WHERE clause, and JOIN conditions of a query.

Example 1

In the Orders table the NorthWind database, there currently is a non-clustered index on the ShippedDate column.

Try running the following:

SELECT ShippedDate, shipcity FROM orders WHERE ShippedDate > '8/6/1996'

The query plan of statement produces a Clustered Index Scan.

Now add the column shipcity to the non-clustered index on ShippedDate.

CREATE INDEX [ShippedDate] ON [dbo].[Orders] ([ShippedDate], [ShipCity]) WITH DROP_EXISTING

Now run the query again. This time, the query plan of statement produces an Index Seek.

This magic happened because all fields (ShippedDate and ShipCity) in the SELECT and the WHERE clauses are part of an index.

Example 2

In the Titles table of the Pubs database, check out the following execution plan for this query:

SELECT title_id, title FROM titles WHERE title LIKE 't%'

Notice that the execution plan shows an Index Seek, not a Bookmark Lookup (which is what you usually find with a non-clustered index). This is because the non-clustered index on the Title column contains a clustered index key Title_Id, and this SELECT has only Title_Id, Title in the SELECT and in the WHERE clause.

 

Now the Hard Part Starts

By following the simple steps outlined here, you get useful pieces of information in no time that can help you improve the performance of your database. After you have data in front of you put it to work. These minor inputs will bring a majority of your results.

 

Published with express written permission of the author. Copyright 2002.

'programming > MSSQL' 카테고리의 다른 글

[Tip]mdf파일 만으로 DB 복구하는 방법  (0) 2003.11.12
[튜닝] index...  (0) 2003.10.14
SQL Server에서 Blocking을 줄이기 위한 전략!!  (4) 2003.10.06

태국쪽 DB서버의 CPU사용량이 갑자기 증가되어 그 원인을 찾던 중...

그 문제가 index에 있는것을 알았다.

헐... 데이터라고는 고작 12000row 정도 밖에 없는 테이블인데...

 

그 테이블에 인덱스가 없다고.. cpu사용량이 70%까지 올라갔다가..

index하나 만들어주니 20%이하로 줄다니...

 

하여간 항상 index를 제일 먼저봐야겠다는 생각을 다시 한번 했다.

 

출처 : http://www.sql-server-performance.com

읽어보시면 알겠지만, 많은 도움이 됩니다.
영어를 잘 못하는 관계로 해석 되는거 같은 부분만 번역 달아 놓겠습니다. 혹시 틀린 부분이 있으면 답글 부탁드립니다. 바로 정정하겠습니다.
번역 안되어 있는 부분 번역해 주시면 바로 원문에 반영하겠습니다.

Strategies to Reduce SQL Server Blocking
(SQL Server Blocking을 줄이기 위한 전략)

by Sancho Fock

No reasonable strategy for the resolution of SQL Server blocking problems can be found until one has determined the precise nature of the block. The most obvious criterion for distinguishing between different blocking issues is their average duration.
The following categories emerge as a result of this division:

Short-time Blocking: Average duration less than three seconds.
(짧은 시간 블러킹 : 평균 3초 이하의 수행 시간을 갖는 트랜잭션)

Mid-time Blocking: Average duration ranges from 3 seconds to a maximum of 10 minutes.
(중간 시간 블러킹 : 평균 3초 ~ 10분 이하의 수행 시간을 갖는 트랜잭션)

Long-time Blocking: Average duration more than 10 minutes.
(긴 시간 블러킹 : 10분 이상의 수행 시간을 갖는 트랜잭션)

Deadlocks: In theory, there is no limit to the duration, and because of this, SQL Server automatically terminates one of the blocked processes.
These four different types of blocks are discussed below in terms of their possible causes and in reference to the appropriate strategies for resolving them.


Short-Time Blocking
(짧은 시간 블러킹)

Short-term blocking is inevitable in multi-user databases.
(짧은 시간의 블러킹은 다중 사용자 데이터베이스에서는 피할 수 없다.)
Normally, they represent no problem for the operation of an application.
Nevertheless, these types of blocks should be investigated in cases where they have begun to occur to only a few users or where they occur very frequently.
(그렇지만, 사용자가 적을때 발생하거나, 매우 자주 발생한다면 원인을 찾아야한다.)
If these blocks appear frequently, it can lead to a snowball effect and eventually paralyze the entire system.
(만약 블러킹이 매우 자주 발생된다면, snowball 효과로 인하여 (이게 뭔지 아시는 분 ^^;;) 전체 시스템의 마비를 가져오게 된다.)

Even in cases where it is likely that the problem cannot be completely solved, one should nevertheless at least attempt to defuse it.


Causes of Short-Term Blocking
(짧은 시간의 블럭킹이 발생하는 원인)

Short-time blocking, which occur very frequently, can be traced back to the following basic problem: the total performance capacity of the system is not enough for the current user load.
(짧은 시간의 블러킹은 다음과 같은 일반적인 문제로 인해 매우 빈번히 발생된다. : 시스템이 현재 전체 사용자의 부하를 견디지 못하는 경우.)

Resolution Strategies for Short-Term Blocking
(짧은 시간의 블러킹 해결 방안)

Such problems can best be met by carrying out an extensive performance tuning of the server and of the application. If this situation does not occur until there is a very high user load, then one should begin the investigation by examining the server and the network.

However, if this situation begins to occur with low user load levels, then one should investigate whether certain use cases of the client application are able to block one another or even themselves in conceptual terms. If this should be found to be the case, then an investigation needs to be carried out to determine whether the probability of the occurrence of this unwanted situation can be reduced through atomic transactions or the use of "row-level locking" or similar strategies.



Mid-Time Blocking
(중간 시간 블러킹)

This type of scale block is the most difficult to find.
(이 정도 크기의 블럭은 가장 찾기 힘든 경우이다.)

It lasts long enough to bring the operation of an application to a stop, but at the same time is still generally too short for manual analysis.
Support for this ability is available with THS Software's SQL Guard 2000. A demo version of SQL Guard 2000 can be downloaded free-of-charge from www.thsfock.de.


Causes of Mid-Time Blocking
(중간 시간 블러킹의 원인)

The possible causes for this type of block are the following:

(이런 종류의 블러킹의 원인이 될만한 것들은 아래와 같다.)

- Transactions which are (too) complex.
(트랜잭션이 매우 복잡한 경우)

- Extremely important interrogations in a transaction.

- Non-error-free interrogations in transactions (e.g. unintended cross-joins).

- User interaction within transactions (e.g. message box "Should data really be deleted?").
(트랜잭션 내의 사용자 interaction(예를들면 '이 데이터를 지우겠습니까?'라는 메세지 박스)

- Unnecessarily time-consuming processing within transactions.

- Unnecessarily distributed processing with high data transport volumes.
(불필요한 많은 양의 데이터를 분산 처리하는 일)

- Snowball effect of short-time scale blocks.

Resolution Strategies for Mid-Time Blocking

(중간 시간 블럭킹의 해결 방안)

Once one has established which transactions are blocking other processes ? e.g. with the help of SQL Guard ? a determination must be made as to which type of error is present.

The following questions emerge in cases of complex transactions:

- Can the transaction be simplified?
(트랜잭션을 보다 간단하게 만들 수 있는가?)

- Can the transaction be divided up into smaller parts?
(트랜잭션을 작은 부분들로 나눌 수 있는가?)

- Can the transaction be greatly accelerated through performance optimization?
- Can the transaction be carried out at a later time (e.g. a nighttime job)?
- Could the transaction also use separate resources (e.g. temporary tables) in order to carry out the actual modifications in concentrated fashion if successful?
- Can the data transport within the transaction be reduced (e.g. swapping processing out into SP's)?
- Does the transaction block resources unnecessarily (e.g. a SELECT which locks lookup tables)?

These questions offer approaches for solving the problem. Should it happen that all of the questions are to be answered in the negative, then one is faced with the choice of either accepting the situation as it is, or of thinking through the business processes to find a way to replace the problematic transactions with others as necessary.



Additional Mid-Time Resolution Strategies
(추가적인 중간 시간 트랜잭션의 블러킹 해결 전략)

If the transaction involves extremely important interrogations, replace them with faster ones.


If user interactions ? such as message boxes ? take place during database transactions, then these must be eliminated! User interactions have lost absolutely nothing within database transactions. Make sure without fail that your client programmers are also aware of this. Programmers with a background in desktop database development are particularly susceptible to having frequent problems distinguishing between business transactions and database transactions.


The same holds true for unnecessarily time-consuming processing within the transaction as much it does for more complex transactions. You could however also ask yourself the question, "Does this processing really have to take place within the transaction?"


In cases where a large amount of data is transported from the server to the client within a transaction, this should be minimized where possible. The processing of x-amount of data is fundamentally just as fast at the client end as it as on the server. The bottleneck is as a rule the transport through the network. Therefore, always carry out the processing at the place where most of the necessary information is to be found. For example: if one needs only to know the total number of certain types of data sets (and not to have the data sets themselves), then using a "select count(*)" will always be faster than even the most wonderful algorithm at the client end (because the client first needs to obtain all the data via the network). If, on the other hand, an SP requires kilobytes of parameters, then the client may be considerably faster.


If a snowball effect is present, then follow the strategies used against short-time scale blocks.


Long-time Blocking
(장시간의 블러킹)


These blocks are very similar to mid-time scale blocks. As a general principle, they can also have the same causes as the mid-time scale blocks.
이런 블러킹은 중간 시간 정도의 블러킹과 매우 유사하다. 일반적인 이론에 의하면, 이런 장시간 블러킹의 원인은  중간 시간 정도의 블러킹 원인과 같다.)

 

In addition, they can have the following causes:
(추가적으로 아래와 같은 것들이 원인일 수도 있다.)


Unintentionally non-closed transactions, and Endless loops within transactions

(실수로 transaction을 종료하지 않는 경우나 트랜잭션 안의 무한루프)


The following applies to both causes: their durations could fall within the mid-time scale block range if, for example, transaction timeouts have been defined or if the end user shuts down his client.


Resolution strategy for Log-Time Blocking

(장시간 블러킹 해결 방안)

The resolution strategy for both of the additional causes is clear: eliminate the error(s).
(추가적인 두가지 원인의 해결 방안은 확실하다 : 에러를 없애라)


The Special Case of Deadlocks
(데드락의 특별한 경우)


In view of the fact that a great deal of information concerning deadlocks is readily available in the relevant literature, they will be treated only briefly here: deadlocks are a special case in terms of scale blocks, because there is no unambiguously "guilty party" in such situations.

SQL Server is also very adept at recognizing and treating deadlocks, as you will find when you read the SQL Server documentation. Essentially, SQL Server does the same thing against deadlocks that the SQL Guard 2000 does against blocks: it terminates a process. The only difference is that the SQL Server recognizes no guilty party when faced with a deadlock, and therefore selects a "victim".

One can never completely exclude deadlocks from larger systems. The strategies used to reduce their quantity are the same as those that can be used to avoid blocks in general. In addition, one can take care to ensure that there are no transactions present which require the same resources in the reverse order.



A Summary of the General Strategies
and Guidelines for Reducing SQL Server Blocking
(SQL 서버의 블러킹을 줄이기 위한 일반적인 전략과 가이드 라인)

* Forbid user interactions in transactions.
(트랜잭션 안에 사용자와의 interaction(입력을 기다린다던가 하는 작업)을 금한다.)

* Always keep transactions as limited in size and as brief as possible.
(트랜잭션은 항상 가능한 한 짧은 시간동안 최소한의 범위를 유지해야 한다.)

* Use no unnecessary resources in transactions.
(트랜잭션 안에서는 불필요한 리소스는 사용하지 않는다.)

* Carry out as little external processing as possible during a transaction.

* Always select with the option "with no locks" except in cases where you have an important reason for doing otherwise.

(다른 중요한 이유로 뭔가를 수행하는 경우가 아니라면, 항상 SELECT 구문에 'with no locks' 옵션을 사용하라.)


* Use row level locking.
(row단위 락킹을 사용한다. 예를 들면 from tableName WITH (NOLOCK)과 같이)

* Use "dirty reads" wherever possible (never make this option global, because it is not possible except with only a very few interrogations).

(가능하면 'dirty reads'를 이용하라


* Performance tune your systems as much as possible.
(가능한 한 많은 시스템 성능 튜닝을 한다.- 당연한 얘기 --;;)

* Carry out necessary complex transactions such as invoicing at times when the user load is as low as possible.

* Schedule maintenance tasks which put extra loads on the server (e.g. Full Backup, defragmentation of indexes) at times when the user load is minimal (nights, weekends)
(서버에 추가적인 부하를 주는 maintenance task(예를 들면, DB Full Backup, index 조각모음)의 스케쥴은 서버의 부하가 최소인 시간으로 잡는다.

* Always select as little as possible and only as much as is necessary.
(가능한한 적은 row만을 Select하고, 꼭 필요한 만큼만 Select한다.)

Sancho Fock has been a freelance software developer since 1995. His professional area of concentration is the object-oriented software development of applications using two or more layers. In his numerous projects he has accumulated experience with various RDBM's such as MS-SQL Server, Sybase Adaptive Server and Informix. He has had intensive experience with MS-SQL Server in Versions 6.5, 7.x and 8.x (2000). He has become familiar with MS-SQL Server in his various roles as a T-SQL developer, an applications developer and as a database administrator. Contact him at: sancho@thsfock.de Visit his website at: www.thsfock.de.

Published with the express written permission of the author. Copyright 2003.

'programming > MSSQL' 카테고리의 다른 글

[튜닝] index...  (0) 2003.10.14
VB프로그래밍 시 DB서버에 접속이 안되는 경우  (0) 2003.07.28
SQL 서버 이름을 바꾸고 시플땐~  (0) 2003.07.28
Set cnn1 = New ADODB.Connection
cnn1.Provider = "sqloledb"
cnn1.Open "Data Source=210.102.25.102;Initial Catalog=pubs;Network Library=dbmssocn;", "sa", ""


일반적으로 Connection String에 Network Library를 명시하지 않는데... 그것이 문제였다.

명시하지 않으면 Named Pipes를 사용하여 서버에 연결하거든!

dbnmpntw - Win32 Named Pipes
dbmssocn - Win32 Winsock TCP/IP
sp_dropserver old_server_name
exec sp_addserver new_server_name, local
go

라고 하시거나..
더 속편하게.. SQL서버7 시디를 넣고 setup을 돌리시면?
이를 다시 보정해 줍니다.(DB는 이상 없지요)


아울러 EM은 클라이언트 툴입니다.
새롬 데이터맨을 삭제해도 하이텔은 돌아 가는것과 마찬가지 이지요.
EM에서 delete레지스트레이션 하신후 다시 등록 하시면?
잘 되실 겁니다.

그럼 이만.

간단합니다.

regrebld Utility
Use the regrebld utility to back up or restore the Microsoft SQL
Server registry entries if they become corrupted.

regrebld -restore
하심 바로 해결 됩니다.
참고로 NT를 재설치 했을때도 역시 유용 합니다.
서버 이름이 빠뀜도 역시 마찬가지 입니다.
그럼 이만.
Trigger가 걸려있는 테이블에 Insert한 후 @@IDENTITY를 하면 Trigger가 걸린 테이블이 ID컬럼을 갖는 경우 @@IDENTITY값이 틀릴 수 있다. 그러므로 아래와 같은 문장을 이용할 것

IDENT_CURRENT('table_name')
DBCC CHECKIDENT (tblChargeCardDepositTemp , RESEED , 0)

+ Recent posts