안녕하세요. 마리입니다. ^^;

 

이 팁은 ADO와 SQL에 관한 팁입니다. 많은 페이징 쿼리가 있지만....

 

성능때문에 말들이 참 많았죠? 이 팁 또한 그러한 말들 중에 대안을 내 놓은 그런 팁인듯 합니다.

 

참고 많이 하시구요. 어려우신 부분은 질문을 해주세요. 맨 아래쪽 SP가 진국인데...

 

초보분들이 보시기에는 복잡한 듯 합니다.

 

 

SQL Server에서 사용할 수 있는 서버측 페이징기법 

Andrew Rosca 

웹 애플리케이션은 일반적으로 사용자에게 많은 양의 정보를 제공하기 위해 페이징 기법을 사용한다. 
예를 들어 인터넷 검색엔진은 사용자의 쿼리 결과로 대용량의 결과값을 반환한다. 
이 때 검색엔진이 한번에 결과값 전체를 반환하게 되면 결과값을 받는 클라이언트측 시스템에 과부하가 발생할 수 있다. 
하지만 페이징 기법을 사용하게 되면, 반환되는 결과값을 클라이언트측과 서버측 양쪽에서 관리할 수 있을 만큼의 고정된 크기의 블록으로 구분하여 한 번에 이동시키는 정보의 양을 줄일 수 있다. 애플리케이션에서는 한 번 에 소수의 레코드만 사용자에게 보내게 되며, 결과값 중에서 사용자가 필요로 하는 정보만 반환하게 된다. 

페이징 기법을 사용하면 데이터를 사용자가 좀 더 이해하고 표현하기 쉽게 해 줄 뿐만 아니라, 대량의 정보를 조회하고 표현하기 위해서 시스템에 불필요한 과부하가 발생하여 결국 시스템의 성능에 악영향을 미치지 않도록 통제하기 때문에 전체적인 시스템 성능을 향상시키게 된다.
정상적으로 시스템에 반환된 결과값 레코드가 페이징되었다면, 검색엔진을 사용하는 사용자는 대부분 맨 처음 한 페이지 또는 일부 페이지만 조회하게 될 것이다. 

불행하게도 많은 프로그래머들이 페이징 관련해서 성능측면에서 매우 중요한 고려사항에 대해서 잘 모르고 있다. 
IIS와 SQL Server를 사용하는 환경에서는, 
AbsolutePage, PageSize, PageCount와 같은, 
표준 ADO RecordSet 페이징 기능을 사용하는 것이 가장 일반적인 페이징 기법이다. 
소량(수십 또는 수백 레코드 정도)의 데이터에 대해서는 이러한 기능을 사용하면 정상적으로 동작하고, 시스템의 성능측면에서도 부하를 발생시키지 않는다. 하지만 레코드 수가 증가하게 되면, 이러한 기능을 사용하게 되면 효율성이 감소하게 되고 전체적인 애플리케이션의 성능에 악영향을 미치게 된다. 

대량의 발주정보를 조회해야 하는 구매조달관련 애플리케이션, 수 천명의 회원이 동시에 접속하는 미팅 웹사이트, 고객의 검색조건에 따라 수백 개의 상품의 정보를 표시해야 하는 대규모 전자상거래 웹사이트와 같이, 대용량 데이터를 처리해야 하는 애플리케이션의 경우에는 좀 더 개선된 서버측 페이징 기술이 필요하게 된다. 이번 호의 기사에서는 수백만 개의 행정보를 포함하는 테이블에서도 사용할 수 있는 페이징 기법에 대해서 소개하고자 한다. 


ADO RecordSet 페이징 기법의 한계 


대용량의 레코드를 페이징하기 위해서 ADO RecordSet의 페이징기법을 사용할 때 발생하는 문제의 원인은 ADO에서 데이터를 처리하는 방법 때문이다. 
ADO 기술구조에서는 데이터베이스에서 정보를 조회하기 위해 서 조회의 대상이 되는 데이터에 대한 포인터를 관리해야 할 필요가 있다.
데이터에 대한 포인터를 커서 라고 하며, 클라이언트측(예를 들어 ASP 페이지)에서는 각 레코드를 건별로 조회하게 된다. 

ADO RecordSet 개체는 서버측 커서(기본값)와 클라이언트측 커서 유형을 지원한다.
서버측 커서를 사용하게 되면 모든 데이터는 그대로 SQL Server에 두고, 해당 데이터가 필요한 시점에 순서에 따라 각 레코드를 조회하게 된다.
클라이언트측 커서를 사용하게 되면 필요한 모든 데이터를 클라이인트로 전송한 다음, 클라이언트측 커서를 사용하여 클라이언트측 버퍼 메모리에 있는 데이터를 레코드별로 조회하게 된다. 
검색엔진 예제에서처럼 쿼리의 결과값 중에서 일부분만을 표시하거나 사용해야 하는 경우라면 SQL 서버가 클라이언트에서 요청하는 페이지만 전송하고 전체 결과값 중 나머지 레코드는 데이터베이스 서버에 그대로 남겨두게 되는, 서버측 커서를 사용하는 것이 효율적이다.
서버측 커서를 사용하게 되면 클라이언트로 전송되는 레코드 수가 특정 페이지를 구성하는 20~30 레코드 정도로 제한된다는 것이다. 

PageCount 와 같은 일부 레코드셋 페이징 기능을 사용하기 위해서는 클라이언트측 커서를 사용해야 한다.
클라이언트 커서를 사용할 수 있도록 ADO를 설정하기 위해서는 RecordSet의 ClientLocation 속성을 adUseServer에서 adUseClient로 변경해 주면 된다.
[리스트 1]의 VB 코드는 RecordSet 개체에서 클라이언트측 커서와 서버측 커서를 사용하는 방법에 대한 예제가 나타나 있다. ClientLocation 속성을 asUseClient 로 변경하게 되면, 사용자 쿼리의 결과로 반환되는 데이터에서 필요로 하는 페이지 수를 판단하기 위해 결과값 전체가 클라이언트로 전송된다. 

예를 들어 데이터베이스로부터 5000 레코드를 반환하는 쿼리를 실행했다고 가정하자.
애플리케이션에서 서버측 커서를 사용하게 되면 반환되는 레코드를 한 페이지당 20 레코드씩으로 페이징하고, 사용자가 1 페이지만 보고 있는 경우라면 애플리케이션에서는 클라이언트로 맨 처음 페이지를 구성하는 20 레코드만을 전송하면 된다.
그 다음 사용자가 두번째 페이지로 이동하면 애플리케이션에서는 21~40번 레코드만 클라이언트로 전송하게 된다. 반면에 클라이언트측 커서를 사용하게 되면 ADO에서는 비록 사용자가 단지 첫 페이지에 해당하는 20 레코드만 필요한 경우라도 5000 레코드 전체를 클라이언트로 전송하게 된다.
이렇게 전체 레코드를 전송하게 되면 결과값이 사용자에게 나타나는 시간이 지연되게 되고, 반환되는 레코드 수가 매우 많은 경우에는 성능에 심각한 악영향을 미칠 수 있다. 

다른 페이징 기법 

ADO RecordSet 페이징 기법과 관련한 문제가 애플리케이션의 성능에 영향을 미치게 되었기 때문에 필자는 수천 레코드를 페이징해야 하는 웹 애플리케이션에서 사용할 수 있는 다른 페이징 기법을 찾아 보았다. 

SQL 서버의 인덱스를 활용하여 전체 결과집합 중에서 상위의 레코드를 선택하는 방법을 소개하고자 한다. 

다음은 Northwind 데이터베이스의 Orders 테이블에서 상위 10개의 레코드를 선택하는 쿼리이다.

SELECT TOP 10 * FROM Orders 

위의 구문을 활용하면 전체 결과집합에서 10 개의 레코드 단위로 결과값이 반환되게 할 수 있다.
주어진 페이지에 해당하는 레코드만 선택하기 위해서는, 한 페이지에 몇 개의 레코드를 포함시킬 것인지 결정하고, 실제 사용자가 몇 번째 페이지의 정보를 조회하기를 원하는지에 대한 페이지 카운트를 알고 있어야 한다.
예를 들어 한 페이지에 10 개의 레코드가 포함되고, 사용자가 전체 결과값 집합 중에서 3 페이지를 조회하고자 하는 경우라면 다음과 같은 쿼리를 사용하면 된다. 

SELECT TOP 10 * FROM Orders WHERE OrderID NOT IN (SELECT TOP 20 OrderID FROM Orders) 

위의 쿼리는 맨 처음 20 개의 레코드 이후에 존재하는 10개의 레코드, 즉 21~30번까지의 레코드를 반환한다. 위의 쿼리를 절차코드로 일반화하게 되면 다음과 같이 표현할 수 있다. 

SELECT TOP page_size * FROM Orders WHERE OrderID NOT IN (SELECT TOP (page_size * (current_page - 1)) OrderID FROM Orders) 

위의 쿼리는 대량의 레코드를 반환하는 경우라도 잘 동작하지만, 반환할 페이지의 숫자가 많아질수록 전체적인 성능은 감소하게 된다.
문제의 원인은 IN 연산자에 포함되는 쿼리의 결과값이 많아지면서 비효율성이 증가하기 때문이다. 예를 들어 한 페이지당 10개의 레코드를 반환하는 결과집합 중에서 500번째 페이지를 조회하기 위해 쿼리를 실행하게 되면, IN 연산자의 대상이 되는 서브쿼리에는 다음과 같은 문장이 포함되게 된다. 

(SELECT TOP 4990 OrderID FROM Orders) 

마지막 10개의 레코드를 조회하기 위해 서버에서는 4990 개의 OrderID와 각 OrderID를 비교해야만 한다.
불필요한 비교작업이 많이 발생하게 된다. 
물론 SQL Server의 경우에는 이러한 경우 데이터를 좀 더 빠르고 효율적인 방법으로 검색하기 위해서 인덱스를 사용하여 빠르게 쿼리를 처리하게 된다.
(OrderID가 기본키로 설정되어 있기 때문에, SQL Server는 기본적으로 인덱스를 사용하게 된다.) 
조회하고자 하는 페이지 수가 증가함에 따라 성능면에서 느려지게 된다고 하더라도 이러한 조회성능의 감소현상은 조회하고자 하는 페이지 수가 매우 큰 경우에만 인식할 수 있게 된다.
이러한 점증적인 성능의 감소현상은 대부분의 경우 사용자가 맨 처음부분의 일부 페이지만 조회하게 되고, 맨 처음부분의 일부 페이지를 조회 할 경우에는 매우 빠른 성능을 보장할 수 있기 때문에 크게 중요한 관심의 대상이 되지 않는다.
애플리케이션이션에서 적절하게 데이터를 정렬하고 필터링한다면 사용자는 찾고자 하는 정보를 거의 한 두 페이지 이내에서 찾게 된다. 만약 맨 처음 부분의 페이지에서 필요로 하는 데이터를 찾지 못한 경우에는 대부분의 사용자는 예제에서처럼 500 페이지까지 원하는 데이터를 찾고자 계속 다음 페이지를 찾아보는 것이 아니라 다른 정렬 및 필터링 조건으로 새로운 쿼리를 하게 된다. 

앞에서 언급한 것과 같이 검색작업을 수행할 때, 테이블의 기본키가 어떤 컬럼에 설정되었는지가 매우 중요한 역할을 하게 된다.
기본키에는 각 레코드를 유일하게 식별할 수 있는 컬럼이 포함되어야 하며, 쿼리를 실행할 때 기본키를 기준으로 해당 레코드를 쿼리의 결과값으로 선택할 것인지 무시할 것인지를 판단하게 된다.
앞의 일반화된 쿼리에는 정렬 및 기본키에 관련한 WHEHE 절이나 ORDER BY 절 내용이 누락되어 있다. 목록 2에는 이러한 요소를 포함시킨 일반화된 쿼리가 나타나 있다. 

정렬은 일반적으로는 비효율적인 작업이며, 쿼리의 성능을 저하시키는 원인이 되기도 한다.
SQL 서버의 경우, 인덱스가 설정된 컬럼에 대해서는 매우 효율적으로 정렬 및 필터링 작업을 할 수 있고, SQL 서버가 항상 기본키 컬럼에는 인덱스를 생성하기 때문에 쿼리를 좀 더 최적화하여 빠르게 실행한다.
기본키에 설정된 인덱스를 최대한 활용하기 위해서, [리스트 3]과 같이 테이블의 전체 컬럼을 선택하지 않고, 먼저 기본키의 조건으로 대상이 되는 레코드를 검색한 다음에 결과값에 포함되어 있는 기본키값으로 다시 해당 레코드에 대한 전체 컬럼을 찾아오게 할 수도 있다.
테이블에 기본키 인덱스가 설정되어 있고, 인덱스가 설정된 필드에 대해서만 정렬 및 필터링 작업을 하게 되면, 조회하고자 하는 레코드를 찾기 위해 인덱스 페이지만을 사용하게 된다. 이렇게 쿼리의 결과값에 필요한 전체 필드가 인덱스에 포함되어 있는 경우를 커버된 인덱스라고 한다.
동일한 쿼리를 실행시킨 경우라도 해당 쿼리가 커버된 인덱스를 사용하는 경우가 일반 테이블에 대해서 쿼리하는 경우보다 더 빠르게 된다. 맨 마지막으로 선택된 결과값에 해당하는 나머지 정보를 조회하기 위한 작업을 수행할 때에는(즉, SELECT * 부분), 기본키 인덱스를 사용하여 SQL Server가 해당 인덱스를 바로 찾을 수 있기 때문에 매우 효율적으로 쿼리를 수행하게 된다. 

[리스트3]에 나타나 있는 쿼리는 결과집합 중에서 특정 페이지를 매우 효율적이고, 단순한 방법으로 조회하게 된다. 물론, GROUP BY나 HAVING 절을 추가하여 사용할 수도 있다. 
쿼리를 좀 더 단순화하기 위해서 [리스트 4]와 같이 SELECT_WITH_PAGING 라는 저장 프로시저를 생성하여, 기능을 캡슐화하였다. 

SELECT_WITH_PAGING 저장프로시저에는 fields_to_return (string), primary_key (string), table_name (string), page_number (integer, default 1), page_size (integer), get_record_count (true/false), filter_conditions (string), sort_columns (string), group_by (string)와 같은 매개변수(데이터형)가 입력되게 된다. 

예를 들어 한 페이지당 레코드 수를 10개로 지정하고 Northwind 데이터베이스의 Order 테이블으로부터 주문일자로 정렬하여 CustomerID, ShipName을 조회한 다음, 결과값 중 세번째 페이지를 조회하기 위해서는 다음 문장을 실행하면 된다. 

EXEC SELECT_WITH_PAGING 'CustomerID, ShipName', 'OrderID', 'Northwind.dbo.Orders', 3, 10, 1, '', 'OrderDate' 

위의 쿼리를 실행하게 되면 입력된 조건에 따라 필터링되어 반환되는 전체 레코드 수가 두번째 레코드셋으로 반환된다. 전체 레코드 수는 사용자에게 전체 페이지 수를 표시하려고 할 때 유용하게 사용되며, 대부분의 경우 사용자는 단순하게 이전페이지 또는 다음페이지로 표시되는 것보다는 전체 페이지 수 중에서 현재 조회하고 있는 페이지의 번호를 표시하는 방법을 더 선호한다. 
조건에 해당하는 전체 레코드 수를 조회하기 위해서 필자는 여섯번째 매개변수를 1로 설정하였다. 
만약 여섯번째 매개변수를 설정하지 않으면 데이터베이스로부터 페이지당 레코드로 제한된 10개의 레코드만을 반환하게 되기 때문에 전체 레코드 수가 몇 개인지는 알 수 없게 된다. 

table_name 매개변수에는 두 개 또는 그 이상의 테이블에 대한 조인을 설정하는 문장이 올 수도 있고, 필요에 따라 서브쿼리도 올 수 있다.
예를 들어, 다음 두 문장은 table_name 매개변수에 모두 사용될 수 있다. 

'Northwind.dbo.Orders A JOIN Northwind.dbo.Customers B ON A.CustomerID = B.CustomerID' '(SELECT * FROM Northwind.dbo.Orders WHERE OrderDate > ''8/1/1996'') AS tbl' 

이번 호의 기사에서 소개한 페이징 기법은 레코드의 수가 매우 많은 경우에 서버측 페이징을 처리하기 위해 매우 단순하고, 효율적으로 사용할 수 있으며, 필자의 경우에는 수백만 행이 포함되어 있는 테이블에 대해서도 사용한 경험이 있다. 예를 들어 2천 5백만 레코드가 있는 테이블에 대해서 맨 처음 일부 페이지를 조회하는 쿼리를 실행할 때, ADO RecordSet 페이징 기법을 사용했을 때에는 거의 40초가 걸렸으나 이번 호에 소개한 저장프로시저를 사용한 경우에는 1초로 수행시간을 단축할 수 있었다.
이처럼 이번 호에 소개한 페이징 기법은 조회의 대상이 되는 데이터양이 많아서 ADO RecordSet 페이징 기법을 사용하게 되면 성능상 문제가 발생할 수 있는 상황에서 유용한 대안으로 사용할 수 있다. 


[리스트 1] ClientLocation 속성을 변경하는 코드 
Dim objConn As ADODB.Connection 
Dim objRS As ADODB.Recordset 
' 연결 생성 
Set objConn = New ADODB.Connection 
objConn.Open "Driver=SQL Server; Server=localhost; Database=Northwind" 
Set objRS = New ADODB.Recordset 
   ' 클라이언트측 커서를 사용하게 하는 옵션 
objRS.CursorLocation = adUseClient 
   ' 서버측 커서를 사용하게 하는 옵션 
   objRS.CursorLocation = adUseServer 
objRS.Open "SELECT * FROM Orders", objConn, adOpenStatic, 
adLockOptimistic 
   ' 이 문장은 페이징을 위해서 필요하지만, 서버측 커서를 사용하는 경우에는 에러의 원인이 된다. 
   Debug.Print "Total records: " & objRS.RecordCount 

[리스트 2] 정렬을 위한 조건절을 지정한 일반화된 페이징 쿼리 
SELECT TOP page_size * FROM table WHERE primary_key NOT IN 
    (SELECT TOP page_size * (page_number - 1) primary_key FROM table 
     WHERE filter_conditions 
     ORDER BY sort_field) 
AND filter_criteria 
ORDER BY sort_field 




[리스트 3] 기본키에 검색조건을 먼저 설정하는 일반화 쿼리 
SELECT * FROM table WHERE primary key IN 
    (SELECT TOP page_size primary_key FROM table
     WHERE primary_key NOT IN

          (SELECT TOP page_size * (page_number - 1) primary_key FROM table 
           WHERE filter_conditions ORDER BY sort_field) AND filter_criteria 
     ORDER BY sort_field) 
ORDER BY sort_field 


[리스트 4] SELECT_WITH_PAGING 저장 프로시저 
CREATE PROCEDURE SELECT_WITH_PAGING ( 
@strFields varchar(4000), 
@strPK varchar(100), 
@strTables varchar(4000), 
@intPageNo int = 1, 
@intPageSize int = NULL, 
@blnGetRecordCount bit = 0, 
@strFilter varchar(8000) = NULL, 
@strSort varchar(8000) = NULL, 
@strGroup varchar(8000) = NULL) 
/* 매개변수에 따라 반환되는 결과값을 특정 페이지로 정의하거나 전체 행을 모두 반환할 수 있도록 설정한다. */ 
AS 
DECLARE @blnBringAllRecords bit 
DECLARE @strPageNo varchar(50) 
DECLARE @strPageSize varchar(50) 
DECLARE @strSkippedRows varchar(50) 
DECLARE @strFilterCriteria varchar(8000) 
DECLARE @strSimpleFilter varchar(8000) 
DECLARE @strSortCriteria varchar(8000) 
DECLARE @strGroupCriteria varchar(8000) 
DECLARE @intRecordcount int 
DECLARE @intPagecount int 
/* 페이징 조건 정규화 의미있는 페이징 조건이 입력되지 않은 경우, 페이징하지 않고 좀 더 효율적인 방법으로 쿼리를 실행시키기 위해 blnBringAllRecords 플래그를 사용 */ 
IF @intPageNo < 1 
SET @intPageNo = 1 
SET @strPageNo = CONVERT(varchar(50), @intPageNo) 
IF @intPageSize IS NULL OR @intPageSize < 1 
?- 페이징하지 않고 전체 행을 반환 
   SET @blnBringAllRecords = 1 
ELSE 
   BEGIN 
     SET @blnBringAllRecords = 0 
     SET @strPageSize = CONVERT(varchar(50), @intPageSize) 
     SET @strPageNo = CONVERT(varchar(50), @intPageNo) 
     SET @strSkippedRows = CONVERT(varchar(50), @intPageSize * (@intPageNo - 1)) 
   END 
/* 정렬 및 필터링 조건 정규화 정렬 및 필터링 조건이 지정되지 않으면, 필터링이나 정렬작업이 수행되지 않도록 하여 쿼리의 성능을 향상시킴.*/ 
IF @strFilter IS NOT NULL AND @strFilter != '' 
   BEGIN 
     SET @strFilterCriteria = ' WHERE ' + @strFilter + ' ' 
     SET @strSimpleFilter = ' AND ' + @strFilter + ' ' 
   END 
ELSE 
   BEGIN 
     SET @strSimpleFilter = '' 
     SET @strFilterCriteria = '' 
   END 
IF @strSort IS NOT NULL AND @strSort != '' 
   SET @strSortCriteria = ' ORDER BY ' + @strSort + ' ' 
ELSE 
   SET @strSortCriteria = '' 
IF @strGroup IS NOT NULL AND @strGroup != '' 
   SET @strGroupCriteria = 'GROUP BY' + @strGroup + ' ' 
ELSE 
   SET @strGroupCriteria = '' 
/* 실제 조회작업을 시작 */ 
IF @blnBringAllRecords = 1 -- 페이징 하지 않고 단순한 SELECT 문장만을 실행 
   BEGIN 

     EXEC ( 
               'SELECT ' + @strFields + 'FROM' + @strTables + @strFilterCriteria + 
               @strGroupCriteria + @strSortCriteria 
               ) 
   END -- 전체 레코드를 반환. 
ELSE -- 지정된 페이지를 반환 
   BEGIN 
     IF @intPageNo = 1 -- 맨 처음 페이지를 찾기 때문에 서브쿼리가 없어서 가장 효율적으로 실

                                 행된다.
        EXEC ( 
                  'SELECT TOP' + @strPageSize + ' ' + @strFields + 'FROM' + @strTables + 
                  @strFilterCriteria + @strGroupCriteria + @strSortCriteria 
                 ) 
     ELSE -- 특정 페이지를 선택하기 위해 서브쿼리 구조를 실행한다. 
        EXEC ( 
                   'SELECT' + @strFields + 'FROM' + @strTables + 'WHERE' + @strPK + 'IN' + ' 
                        (SELECT TOP' + @strPageSize + ' ' + @strPK + 'FROM' + @strTables + 
                       ' WHERE' + @strPK + 'NOT IN' + ' 
                            (SELECT TOP' + @strSkippedRows + ' ' + @strPK + 'FROM' + @strTables + 
                             @strFilterCriteria + @strGroupCriteria + @strSortCriteria + ') ' + 
                             @strSimpleFilter + 
                             @strGroupCriteria + 
                         @strSortCriteria + ') ' + 
                    @strGroupCriteria + 
                    @strSortCriteria 
                 ) 
   END -- 특정 페이지를 지정한 경우 
/* 전체 레코드 수를 반환하도록 지정된 경우 */ 
IF @blnGetRecordCount = 1 
IF @strGroupCriteria != '' 
    EXEC ( 
               'SELECT COUNT(*) AS RECORDCOUNT FROM (SELECT COUNT(*) FROM' + 
                @strTables + @strFilterCriteria + @strGroupCriteria + ') AS tbl (id) 
             ) 
ELSE 
    EXEC ( 
               'SELECT COUNT(*) AS RECORDCOUNT FROM' + @strTables + @strFilterCriteria

               + @strGroupCriteria) 
GO 

출처 : SQL2000 매거진



출처 http://cafe.naver.com/headstudy/713

'Computer > ASP' 카테고리의 다른 글

효율적인 페이징 기법  (0) 2011/11/29
ASP 에서 UTF-8 처리  (0) 2011/11/29
성능 및 스타일 향상을 위한 25+ ASP 팁  (0) 2011/11/29
URLEncode  (0) 2011/11/29
Posted by 알찬돌삐

댓글을 달아 주세요


 
1. 모든 ASP 코드 페이지 첫줄에 다음과 같은 코드를 추가합니다
<% @LANGUAGE='VBSCRIPT' CODEPAGE='65001' %>
 
2. Meta 테그를 다음과 같이 추가 합니다.
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
 
3. 에디트플러스나 울트라 에디터에서 수정후 저장할 때 반드시 Encoding 방식을 UTF-8 로 저장합니다
 
4.DB Insert/Update 시 숫자 타입을 제외한 모든 대상에 N을 추가 합니다
Insert [into] table_name [(column_list)] Value N[data_value]
 
5.DB like 검색시 N 추가
 
6. 파일 첨부 DEXT Upload사용(영문으로 설치)
  1. SET uploadform = Server.CreateObject("DEXT.FileUpload")
  2.  uploadform.DefaultPath = Server.MapPath(ESP_BBS_DATA)
  3.  uploadform.CodePage = 65001
  4.  wFileSize = 0
  5.  rAttachment = uploadform("txtAttachFile")
  6.  
  7.  If Len(rAttachment) > 0 Then
  8.   wFileName =  uploadform("txtAttachFile").FileName
  9.   wFileSize =  uploadform("txtAttachFile").FileLen
  10.  
  11.   response.write uploadform.DefaultPath
  12.   rAttachment = uploadform.SaveAs(uploadform.DefaultPath & "" & wFileName , False)
  13.   rAttachment = UploadForm.LastSavedFileName
  14.  End If
7. 파일 다운로드 

  1. <% @LANGUAGE='VBSCRIPT' CODEPAGE='65001' %>
  2. <%
  3.  'Response.Charset = "UTF-8"
  4.  filepath = Request.QueryString("txtFilepath") '// form으로 파라메터 전달해야 함.
  5.  filename = Request.QueryString("txtFilename")'// form으로 파라메터 전달해야 함.
  6.  
  7.  If filepath = "" Then
  8.   filepath=server.MapPath( Request.QueryString("txtFilename"))
  9.   filename = Mid(filepath, InStrRev(filepath, "")+1)
  10.  Else
  11.   filepath=server.MapPath(filepath)
  12.   filename =  Request.QueryString("txtFilename")
  13.   If filename = "" Then
  14.    filename = Request.QueryString("txtattachment")
  15.   End If
  16.  End If
  17.  
  18.  filepath = filepath &"" & filename
  19. Call FileDown
  20. %>
  21.  
  22. <%
  23. Sub FileDown
  24. ' 참고http://www.taeyo.pe.kr/Lecture/20_TIps/Danny03.asp
  25.  
  26.  Response.Buffer = False
  27.  Response.ContentType = "application/x-msdownload"
  28.  'ContentType 를 선언합니다.
  29.  'server.HTMLEncode
  30.  'server.URLPathEncode
  31.  Response.AddHeader "Content-Disposition","attachment; filename=" & server.URLPathEncode(filename) '//server.URLPathEncode 사용해야만 파일명 재대로 출력
  32.  '헤더값이 첨부파일을 선언합니다.
  33.  Set objStream = Server.CreateObject("ADODB.Stream")
  34.  'Stream 을 이용합니다.
  35.  objStream.Open
  36.  '무엇이든 Set 으로 정의했으면 열어야 겠지요^^
  37.  objStream.Type = 1
  38.  objStream.LoadFromFile filepath
  39.  '절대경로 입니다.
  40.  download = objStream.Read
  41.  Response.BinaryWrite download
  42.  '이게 보통 Response.Redirect 로 파일로 연결시켜주는 부분을 대신하여 사용된 것입니다.
  43.  Set objstream = nothing
  44.  '초기화시키구요.
  45. End Sub
  46. %>
  47.  
  48. <%
  49. Sub DEXTDown   ' DEXT.FileDownload 는 일본어 OS에 영문으로 설치시 한글파일 찾지 못함.(DextUpload 2.0까지는 그랬음)
  50.  'On Error Resume Next
  51.  Response.Buffer = False
  52.  Response.AddHeader "Content-Disposition","inline;filename=" &  server.URLPathEncode(filename)
  53.  set objFS = Server.CreateObject("Scripting.FileSystemObject")
  54.  
  55.  set objF = objFS.GetFile(filepath)
  56.  
  57.  Response.AddHeader "Content-Length", objF.Size
  58.  set objF = nothing
  59.  set objFS = nothing
  60.  Response.ContentType = "application/x-msdownload"
  61.  Response.CacheControl = "public"
  62.  Set objDownload = Server.CreateObject("DEXT.FileDownload")
  63.  objDownload.Download filepath
  64.  Set uploadform = Nothing
  65. End Sub
  66. %>

8. Cdo Mail 발송
  1. Dim iMsg
  2. Dim iConf
  3. Dim Flds
  4. Dim strHTML
  5. Const cdoSendUsingPort = 2 '1:로컬, 2:외부 smtp
  6. set iMsg = CreateObject("CDO.Message")
  7. set iConf = CreateObject("CDO.Configuration")
  8. Set Flds = iConf.Fields
  9. Flds.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = cdoSendUsingPort
  10. Flds.item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25  '포트번호
  11. Flds.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "localhost"
  12. Flds.Item("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 10
  13. Flds.Item("http://schemas.microsoft.com/cdo/configuration/sendusername") =  "" 'ID
  14. Flds.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") =  "" '암호
  15.  
  16. Flds.Update
  17. Set iMsg.Configuration = iConf
  18. iMsg.To = "xxxx@xxx.ccx" 'ToDo: Enter a valid email address.
  19. iMsg.From = "xxxx@xxx.ccx"  'ToDo: Enter a valid email address.
  20. iMsg.Subject = "This is a test CDOSYS message (Sent via Port 25)"
  21.  
  22. 'iMsg..TextBody = strHTMLMsg '// 텍스트
  23. iMsg.HTMLBody = strHTML  '// HTML 제목 깨짐 발생..
  24.  
  25. iMsg.BodyPart.Charset="UTF-8" '/// 한글을 위해선 꼭 넣어 주어야 합니다.
  26. iMsg.HTMLBodyPart.Charset="UTF-8" '/// 한글을 위해선 꼭 넣어 주어야 합니다.
  27. iMsg.Send
  28. End With
  29. Set iMsg = Nothing
  30. Set iConf = Nothing
  31. Set Flds = Nothing 
 
9. ASP에서 배달 확인/ 읽음 확인 구현 방법 http://tong.nate.com/windeo/5767827
  1. <%
  2. Set oMsg = CreateObject("CDO.Message")
  3. oMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
  4. ‘ 생성되는 메시지가 SMTP pickup 디렉터리가 아닌 SMTP 서비스로 전송되게 합니다.
  5. oMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/sendusername") = "이름"
  6. oMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "xxxxx"
  7. oMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "seo-msg-01"
  8. ‘ 생성되는 메시지의 서버, 사서함 및 암호
  9. oMsg.Configuration.Fields.Update
  10.  
  11. oMsg.From = "smpark@microsoft.com"
  12. oMsg.To = "smpark@microsoft.com"
  13.  
  14. oMsg.Subject = "읽음 확인 및 배달 확인"
  15. oMsg.DSNOptions = 14
  16. ‘ 이 메시지의 배달 상태 확인(delivery status notification:DSN)값으로 14는 배달 성공, 실패 및 지연시
  17. ‘ 확인메시지 생성
  18. oMsg.Fields("urn:schemas:mailheader:return-receipt-to") = smpark@microsoft.com <mailto:smpark@microsoft.com>
  19. ‘ 받는 사람이 이 메시지를 열었을 때 읽음 확인 메시지가 여기에서 지정된 사람에게 보내집니다.
  20. oMsg.Fields("urn:schemas:mailheader:disposition-notification-to") = smpark@microsoft.com <mailto:smpark@microsoft.com>
  21. ‘ MDN(Message Disposition Notification)은 이 메시지의 확인 메시지가 리턴 될 수신자를 지정합니다.
  22. ‘ MDN에 대하여는 Request for Comments (RFC) 2298에 자세히 설명됩니다.
  23. oMsg.TextBody = " SMTP 서버를 통한 읽음 확인 및 배달 확인 메시지"
  24. oMsg.Fields.Update
  25. oMsg.Send
  26.  
  27. Set oMsg = Nothing
  28. %>




출처 http://blog.naver.com/lowsky/21899479

'Computer > ASP' 카테고리의 다른 글

효율적인 페이징 기법  (0) 2011/11/29
ASP 에서 UTF-8 처리  (0) 2011/11/29
성능 및 스타일 향상을 위한 25+ ASP 팁  (0) 2011/11/29
URLEncode  (0) 2011/11/29
Posted by 알찬돌삐
TAG ASP UTF-8

댓글을 달아 주세요


Microsoft 컨설팅 서비스, 수석 컨설턴트, Len Cardinal
Microsoft IIS Performance 지도자, George V. Reilly
Microsoft Corporation
개발자 기술 엔지니어
Nancy Cluts의 기사 에서 발췌
최종 수정일: 2000년 4월
요약: 이 기사는 ASP 응용 프로그램 및 VBScript를 최적화하기 위한 팁을 소개합니다.
목차
소개
팁 1: 웹 서버에서 자주 사용되는 데이터 캐시
팁 2: 응용 프로그램 및 세션 개체에서 자주 사용되는 데이터 캐시
팁 3: 웹 서버의 디스크 상에서 데이터 및 HTML 캐시
팁 4: 응용 프로그램 또는 세션 개체에서 활발하지 않은 구성 요소 캐싱 방지
팁 5: 응용 프로그램 또는 세션 개체에서 데이터베이스 연결 캐시 금지
팁 6: 세션 개체의 현명한 사용
팁 7: COM 개체에서 코드 간략화
팁 8: 늦은 리소스 획득, 이른 해제
팁 9: 안정성과 성능을 교환하는 종속 프로세스 실행
팁 10: Option Explicit 사용
팁 11: 서브루틴 및 함수에서 지역 변수 사용
팁 12: 자주 사용되는 데이터를 스크립트 변수로 복사
팁 13: 배열 재정의 방지
팁 14: 응답 버퍼링 사용
팁 15: 일괄 처리 인라인 스크립트 및 Response.Write 문
팁 16: 긴 이동을 시작하기 전에 Response.IsClientConnected 사용
팁 17: 태그를 사용한 개체 인스턴스화
팁 18: ADO 및 다른 구성 요소를 위한 TypeLib 바인딩 사용
팁 19: 사용자 브라우저의 유효성 검사 기능 이용
팁 20: 루프에서 문자열 연결 방지
팁 21: 브라우저 및 프록시 캐싱 사용 
팁 22: 가능한 한 Response.Redirect대신 Server.Transfer 사용
팁 23: 디렉터리 URL에서 후행 슬래시 사용
팁 24: 서버 변수 사용 방지
팁 25: 최신 및 최고급으로 업그레이드
팁 26: 웹 서버 조정
팁 27: 성능 테스트
팁 28: 리소스 연결 읽기
소개
성능은 하나의 기능입니다. 성능을 향상시킬 수 있도록 디자인하거나 나중에 응용 프로그램을 다시 작성해야 합니다. 그러면 ASP(Active Server Pages) 응용 프로그램의 성능을 최대로 발휘할 수 있는 훌륭한 전략에는 어떤 것이 있을까요?
이 기사는 ASP 응용 프로그램 및 Visual Basic?? Scripting Edition(VBScript)을 최적화할 팁을 제공합니다. 이 기사에서는 여러 가지 덫과 함정들을 설명합니다. 이 기사에 열거된 제안은 http://www.microsoft.com 및 다른 사이트에서 검사했으며 매우 잘 작동하였습니다. 이 기사는 사용자가 VBScript 및/또는 JScript, ASP 응용 프로그램, ASP 세션 및 다른 ASP 고유 개체(요청 응답 및 서버)와 같은 ASP 개발을 기본으로 이해하고 있다는 전제 하에 쓰여진 것입니다.
ASP 성능은 ASP 코드 그 자체에 많은 영향을 받습니다. 여기서 우리는 기사에 있는 모든 지혜를 다루는 대신 성능과 관련된 리소스를 열거합니다. 이러한 링크는 ActiveX?? Data Objects(ADO), Component Object Model (COM), 데이터베이스 및 Internet Information Server (IIS) 구성을 포함하는 ASP와 비ASP 주제를 모두 다룹니다. 우리가 선호하는 링크가 있으니 잘 살펴 보십시오.
팁 1: 웹 서버에서 자주 사용되는 데이터 캐시
전형적인 ASP 페이지는 백 엔드 데이터 공간에서 데이터를 검색하고 그 결과를 HTML(Hypertext Markup Language)로 복사합니다. 데이터베이스의 속도와 관계없이 메모리에서 데이터를 검색하는 것은 백 엔드 데이터 공간에서 데이터를 검색하는 것보다 매우 빠릅니다. 로컬 하드 디스크에서 데이터를 읽는 것도 데이터베이스에서 데이터를 검색하는 것보다 더 빠릅니다. 따라서 웹 서버에 있는 데이터를 메모리 또는 디스크에 캐싱하면 성능을 향상시킬 수 있습니다.
캐싱은 시간과 공간을 교환하는 전통적인 방법입니다. 캐시를 올바로 사용하면 성능이 매우 향상된 것을 알 수 있습니다. 캐시를 사용하는 것이 효과적이려면 자주 다시 사용되는 데이터가 있어야 하고 이 데이터를 다시 계산하는 비용이 (적당히) 높아야 합니다. 부실한 데이터를 모두 캐시하는 것은 메모리 낭비입니다.
자주 변경되지 않는 데이터는 데이터베이스 시간 초과와 동시성을 갖을 염려가 없기 때문에 캐싱하기에 적합합니다. 콤보 상자 목록, 참조표, DHTML 스크랩, XML(eXtensible Markup Language) 문자열, 메뉴 항목 및 (데이터 소스 이름(DSN), 인터넷 프로토콜(IP) 어드레스 및 웹 경로를 포함하는)사이트 구성 변수가 캐싱하기에 적합한 것입니다. 데이터 자체보다는 데이터의 프리젠테이션을 캐시할 수 있다는 것을 참조하십시오. ASP 페이지가 자주 변경되고 캐시 비용이 비싸다면(예: 전체 제품 카탈로그) 매번 다시 패인팅하기 보다는 HTML을 미리 생성하도록 하십시오.
데이터를 캐시해야 할 곳은 어디이며 어떤 캐싱 정책이 있습니까? 종종 웹 서버의 메모리 또는 웹 서버의 디스크에서 데이터를 캐시합니다. 다음 두 팁은 이 옵션을 다룹니다.
팁 2: 응용 프로그램 및 세션 개체에서 자주 사용되는 데이터 캐시
ASP 응용 프로그램 및 세션 개체는 메모리 안에 캐싱을 편리하게 해주는 컨테이너를 제공합니다. 응용 프로그램 및 세션 개체에 모두 데이터를 지정할 수 있고 이 데이터는 HTTP 호출 사이에 메모리에 남아 있을 것입니다. 세션 데이터는 각 사용자별로 저장되는 반면 응용 프로그램 데이터는 모든 사용자가 공유합니다.
어느 지점에서 데이터를 응용 프로그램 또는 세션에 로드할까요? 일반적으로 데이터는 응용 프로그램 또는 세션이 시작할 때 로드됩니다. 응용 프로그램 또는 세션이 시작할 때 데이터를 로드하려면 Application_OnStart() 또는 Session_OnStart()에 각각 적당한 코드를 추가합니다. 이러한 함수는 Global.asa에 있어야 하며 없을 때는 이 함수를 추가할 수 있습니다. 가장 필요할 때 데이터를 로드할 수도 있습니다. 이렇게 하려면 데이터가 있는지 확인하고 없을 경우 데이터를 로드하도록 ASP 페이지에 몇 가지 코드를 추가하십시오.(또는 재사용할 수 있는 스크립트 함수 작성) 이것은 필요하다는 것을 알 때 까지 계산을 하지 않는 지연 평가라는 전형적인 성능 기술의 예입니다. 예를 들면 다음과 같습니다.
<%Function GetEmploymentStatusList Dim d d = Application("EmploymentStatusList") If d = "" Then ' FetchEmploymentStatusList function (not shown) ' fetches data from DB, returns an Array d = FetchEmploymentStatusList() Application("EmploymentStatusList") = d End If GetEmploymentStatusList = dEnd Function%>
데이터가 필요한 각 청크를 위해 유사한 함수를 작성할 수 있습니다.
어떤 형식으로 데이터를 저장해야 합니까? 모든 스크립트 변수가 가변형이기 때문에 모든 가변 형식을 저장할 수 있습니다. 예를 들어, 문자열, 정수형 또는 배열을 저장할 수 있습니다. 일반적으로 ADO 레코드 집합의 내용을 이러한 변수 형식 중 하나로 저장할 수 있습니다. ADO 레코드 집합에서 데이터를 얻기 위해 한번에 한 필드에서 수동으로 데이터를 VBScript 변수에 복사할 수 있습니다. ADO 레코드 집합 영구 함수인 GetRows(), GetString()  또는 Save()  (ADO 2.5) 중 하나를 사용하면 더 빠르고 쉽습니다. 이 기사에서는 전체를 자세히 설명하지는 않지만 레코드 집합 데이터의 배열을 반환하기 위해 GetRows()를 사용하는 한가지 함수의 예를 들면 다음과 같습니다.
' Get Recordset, return as an ArrayFunction FetchEmploymentStatusList Dim rs Set rs = CreateObject("ADODB.Recordset") rs.Open "select StatusName, StatusID from EmployeeStatus", _ "dsn=employees;uid=sa;pwd=;" FetchEmploymentStatusList = rs.GetRows() " Return data as an Array rs.Close Set rs = NothingEnd Function
위의 예제를 더 구체화하면 배열이 아닌 목록을 위한 HTML을 캐시할 수도 있습니다. 단순한 예를 들면 다음과 같습니다.
' Get Recordset, return as HTML Option listFunction FetchEmploymentStatusList Dim rs, fldName, s Set rs = CreateObject("ADODB.Recordset") rs.Open "select StatusName, StatusID from EmployeeStatus", _ "dsn=employees;uid=sa;pwd=;" s = "" & vbCrLf rs.Close Set rs = Nothing ' See Release Early FetchEmploymentStatusList = s ' Return data as a StringEnd Function
올바른 조건에서는 응용 프로그램 또는 세션 범위에서 ADO 레코드 집합 그 자체를 캐시할 수 있습니다. 다음과 같은 두 가지 주의 사항이 있습니다.
이러한 두 가지 요구 사항을 충족시킬 수 없다면 ADO 레코드 집합을 캐시하지 마십시오. 아래 있는 Non-Agile Components 및 Don't Cache Connections 팁에서는 응용 프로그램 및 세션 범위에서 COM 개체를 저장하는 것이 위험하다는 것을 설명합니다.
응용 프로그램 또는 세션 범위에서 데이터를 저장하면 이 데이터는 체계적으로 데이터를 변경하거나, 세션이 만료되거나, 웹 응용 프로그램이 다시 시작할 때까지 저장된 곳에 남아 있게 됩니다. 데이터를 업데이트하려면 어떻게 해야 할까요? 응용 프로그램 데이터를 수동으로 업데이트하려면 데이터를 업데이트하는 관리자 전용 ASP 페이지로 이 데이터를 호출할 수 있습니다. 그렇지 않으면 함수를 통해 주기적으로 데이터를 자동으로 새로 고칠 수 있습니다. 다음 예제에서는 캐시한 데이터를 타임 스탬프와 함께 저장하고 일정 기간이 지난 후 데이터를 새로 고칩니다.
<%' error handing not shown...Const UPDATE_INTERVAL = 300 ' Refresh interval, in seconds' Function to return the employment status listFunction GetEmploymentStatusList UpdateEmploymentStatus GetEmploymentStatusList = Application("EmploymentStatusList")End Function' Periodically update the cached dataSub UpdateEmploymentStatusList Dim d, strLastUpdate strLastUpdate = Application("LastUpdate") If (strLastUpdate = "") Or _ (UPDATE_INTERVAL < DateDiff("s", strLastUpdate, Now)) Then ' Note: two or more calls might get in here. This is okay and will simply ' result in a few unnecessary fetches (there is a workaround for this) ' FetchEmploymentStatusList function (not shown) ' fetches data from DB, returns an Array d = FetchEmploymentStatusList() ' Update the Application object. Use Application.Lock() ' to ensure consistent data Application.Lock Application("EmploymentStatusList") = d Application("LastUpdate") = CStr(Now) Application.Unlock End IfEnd Sub
또 다른 예는 응용 프로그램 데이터가 있는 World's Fastest ListBox  를 참조하십시오.
세션 또는 응용 프로그램 개체에서 큰 배열을 캐싱하는 것은 바람직하지 않습니다. 배열의 어떤 요소에 액세스하기 전에 스크립팅 언어의 기능이 전체 배열을 임시로 복사할 것을 요구합니다. 예를 들어, 미국 우편 번호와 지역 기상대를 연결하는 10만개의 요소가 있는 문자열 배열을 캐시할 경우 ASP는 우선 10만개 기상대를 모두 임시 배열에 복사한 후에야 하나의 문자열을 추출할 수 있습니다. 이 경우에는 기상대를 저장하거나 사전 구성 요소 중 하나를 사용하기 위한 사용자 정의 메서드가 있는 사용자 정의 구성 요소를 작성하는 것이 좋습니다.
중요한 것을 놓치지 않기 위해 한 마디 덧붙이자면 배열은 메모리에 인접한 키 데이터 쌍을 빨리 조회하고 저장할 수 있도록 합니다. 사전을 인덱싱하는 것은 배열을 인덱싱하는 것 보다 느립니다. 자신의 상황에서 최상의 성능을 제공하는 데이터 구조를 선택해야 합니다.
팁 3: 웹 서버의 디스크 상에서 데이터 및 HTML 캐시
때때로 데이터가 너무 많아서 메모리에서 캐시할 수 없는 경우가 있습니다. "너무 많다"는 것은 판단력에 근거한 것으로 캐시할 항목의 수와 이 항목을 검색하는 빈도뿐 아니라 소비할 메모리의 양과도 관계가 있습니다. 어떤 경우든 메모리에서 캐시하기에 데이터가 너무 많을 때는 웹 서버의 하드 디스크 상에서 텍스트 또는 XML 파일로 데이터를 캐시할 수도 있습니다. 상황에 가장 적합한 캐싱 정책을 세우기 위해 데이터를 캐싱하는 데 메모리와 디스크를 같이 사용할 수 있습니다.
단일 ASP 페이지의 성능을 측정할 때는 디스크에서 데이터를 검색하는 것이 데이터베이스에서 데이터를 검색하는 것보다 느릴 수도 있다는 것을 참조하십시오. 그러나 캐싱은 데이터베이스 및 네트워크에서 로드를 줄여줍니다. 로드가 높을 때 캐싱은 전체적인 성능을 향상시킵니다. 다중 테이블 조인 또는 복잡한 저장 프로시저와 같은 부담이 큰 쿼리의 결과를 캐싱하거나 큰 결과 집합을 캐싱하는 경우 캐싱은 매우 효과적입니다. 언제나 처럼 경쟁하는 여러 가지 계획을 테스트하십시오.
ASP 및 COM은 디스크 캐싱 계획을 세우기 위한 몇 가지 도구를 제공합니다. ADO 레코드 집합 Save() 및 Open() 함수는 디스크에서 레코드 집합을 저장 및 로드합니다. 앞서 언급한 응용 프로그램 데이터 캐싱 팁으로부터 예제 코드를 다시 작성하기 위해 이러한 메서드를 사용할 수 있습니다. 위의 팁에서는 파일로의 Save() 함수가 응용 프로그램 개체에 작성하는 코드를 대신합니다.
파일로 작업하는 다른 몇 가지 구성 요소가 있습니다.
  • FileSystemObject를 스크립트  하면 파일을 생성, 읽기 및 작성할 수 있습니다.
  • Internet Explorer와 함께 제공되는 Microsoft?? XML 파서인 MSXML은 XML 문서를 저장 및 로드할 수 있도록 합니다.
  • The LookupTable 개체(예제, MSN에서 사용)는 디스크에서 단순한 목록을 로드하는 데 가장 적합합니다.
마지막으로 디스크에 데이터 자체보다는 데이터의 프리젠테이션을 캐싱하도록 하십시오. 미리 렌더링된 HTML은 디스크에 .htm 또는 .asp 파일로 저장되고 하이퍼링크로 이 파일을 직접 가리킬 수 있습니다. XBuilder  , 또는 Microsoft?? SQL Server™ Internet publishing features와 같은 상업용 도구를 사용하여 HTML 생성 과정을 자동화할 수 있습니다. 그 대신 .asp 파일에 HTML 조각을 포함할 수도 있습니다. FileSystemObject를 사용하여 디스크에서 HTML 파일을 읽거나 빠른 렌더링을 위해 XML을 사용  할 수도 있습니다.
팁 4: 응용 프로그램 또는 세션 개체에서 활발하지 않은 구성 요소 캐싱 방지
응용 프로그램 또는 세션 개체에 있는 데이터를 캐싱하는 것은 바람직하지만 COM 개체를 캐싱하는 것은 심각한 위험이 될 수 있습니다. 자주 사용하는 COM 개체를 응용 프로그램 또는 세션 개체에 넣고 싶어지는 경우가 있습니다. 그러나 불행히도 Visual Basic 6.0과 그 이전 버전으로 작성된 모든 COM 개체를 포함하여 많은 COM 개체들이 응용 프로그램 또는 세션 개체에 저장되면 심각한 병목현상을 일으킬 수 있습니다.
특히 구성 요소가 활발하지 않다면 세션 또는 응용 프로그램 개체에서 캐시할 때 성능에 병목 현상이 발생합니다. 활발한 구성 요소는 FTM(Free-threaded marchaler)이 모인 ThreadingModel=Both로 표시된 구성 요소 또는 ThreadingModel=Neutral로 표시된 구성 요소입니다.(Neutral 모델은 Windows?? 2000 and COM+에 새로 도입된 것입니다.) 다음과 같은 구성 요소는 활발하지 않습니다.
  • 빈 스레드 구성 요소(FTM을 모으지 않는 경우)
  • 아파트 스레드 구성 요소
  • 단일 스레드 구성 요소
구성된 구성 요소(Microsoft Transaction Server (MTS)/COM+ 라이브러리 및 서버 패키지/응용 프로그램)는 중립 스레드를 제외하면 활발하지 않습니다. 아파트 스레드 구성 요소 및 다른 활발하지 않은 구성 요소는 페이지 범위에서 가장 잘 실행됩니다.(즉, 단일 ASP 페이지에서 만들고 없앱니다.)
IIS 4.0에서는 ThreadingModel=Both가 표시된 구성 요소가 활발한 것이었습니다. 그러나 IIS 5.0에서는 이것이 더 이상 충분하지 않고 Both가 표시될 뿐 아니라 FTM을 모아야 합니다. 활발함에 대한 기사  는 Active Template Library로 작성된 C++ 구성 요소가 FTM을 모으는 방법을 설명합니다. 구성 요소가 인터페이스 포인터를 캐시할 때 이 포인터는 활발하거나 COM GIT(Global Interface Table)에 저장되어야 한다는 것을 주의하십시오. FTM을 모으기 위해 양쪽 스레드 구성 요소를 컴파일할 수 없다면 그 구성 요소를 ThreadingModel=Neutral로 표시할 수 있습니다. 대신 IIS가 활발함 검사를 수행하지 않게 하려면(따라서 활발하지 않은 구성 요소를 응용 프로그램 또는 세션 범위에 저장하려면) 메타베이스에 AspTrackThreadingModel을 True로 설정할 수 있습니다. AspTrackThreadingModel을 변경하는 것은 바람직 하지 않습니다.
응용 프로그램 개체에서 Server.CreateObject로 작성된 활발하지 않은 구성 요소를 저장하려고 하면 IIS 5.0은 오류를 표시합니다. 이때 Global.asa에서 를 사용하여 이 오류를 피해갈 수 있지만 이렇게 하면 아래에 설명하는 마샬링 및 직렬화가 될 수 있기 때문에 바람직 하지 않습니다.
활발하지 않은 구성 요소를 캐시하면 어떤 문제가 발생합니까? 활발하지 않은 구성 요소를 세션 개체에서 캐시하면 ASP 작업자 스레드로의 세션을 "잠금"으로 만듭니다. ASP는 서비스가 요청하는 작업자 스레드를 유지합니다. 일반적으로 새로운 요청은 처음 사용할 수 있는 작업자 스레드가 처리합니다. 스레드에 대한 세션이 잠기면 요청은 관련 스레드를 사용할 수 있을 때까지 대기해야 합니다. 이해를 돕기 위해 비유를 하자면 다음과 같습니다. 수퍼 마켓에 가서 야채를 사고 3번 계산대에서 계산을 했다면 그 이후에는 수퍼 마켓에서 야채 값을 지불 할 때마다 다른 계산대가 더 한가하거나 비어있어도 3번 계산대에서만 지불할 수 있습니다.
응용 프로그램에 활발하지 않은 구성 요소를 저장하면 성능에 더욱 나쁜 영향을 줍니다. ASP는 활발하지 않은 응용 프로그램 범위 구성 요소를 실행하기 위해 특별한 스레드를 작성해야 합니다. 이것은 두 가지 결과를 초래합니다. 모든 호출이 이 스레드로 마샬링되어야 하고 모든 호출이 직렬화됩니다. 마샬링이 되면 매개 변수는 메모리 공유 영역에 저장되어야 하고, 특별한 스레드에는 비용이 많이 드는 컨텍스트 전환이 이루어지고, 구성 요소의 메서드를 실행하고, 결과가 공유 영역으로 마샬링되며, 비용이 많이 드는 다른 컨텍스트 전환이 컨트롤을 원래 스레드로 돌려주게 됩니다. 직렬화되면 모든 메서드가 한번에 하나씩 실행됩니다. 두 개의 다른 ASP 작업자 스레드가 공유된 구성 요소에서 동시에 실행 메서드가 될 수는 없습니다. 이렇게 하면 특히 다중 프로세서 컴퓨터에서 일관성이 없어집니다. 더욱 나쁜 것은 모든 활발하지 않은 응용 프로그램 범위 구성 요소가 하나의 스레드("Host STA")를 공유하기 때문에 직렬화의 영향이 더욱 뚜렷해지는 것입니다.
너무 복잡합니까? 여기에 몇 가지 일반적 규칙이 있습니다. Visual Basic (6.0) 및 이전 버전에서 개체를 작성할 때는 이 개체를 응용 프로그램 또는 세션 개체에서 캐시하지 마십시오. 개체의 스레딩 모델을 모르는 경우에는 캐시하지 마십시오. 활발하지 않은 개체는 캐싱하지 말고 각 페이지에서 그 개체를 작성하고 릴리스해야 합니다. 이 개체는 ASP 작업자 스레드에서 직접 실행하기 때문에 마샬링 및 직렬화가 일어나지 않습니다. COM 개체가 IIS 상자에서 실행하고 개체를 초기화하고 없애는 데 시간이 오래 걸리지 않는다면 적합한 성능입니다. 단일 스레드 개체는 이런 방법으로 사용하지 마십시오. VB이 단일 스레드 개체를 만들 수 있으므로  주의하십시오! 단일 스레드 개체를 이 방식으로 사용해야 한다면(Microsoft Excel 스프레드시트처럼) 높은 처리 속도를 기대하지는 마십시오.
ADO 레코드 집합이 빈 스레드로 표시되면 ADO 레코드 집합을 안전하게 캐시할 수 있습니다. ADO를 빈 스레드로 표시하려면 일반적으로 Program FilesCommonSystemADO 디렉터리에 있는 Makfre15.bat 파일을 사용합니다.
주의: Microsoft Access를 데이터베이스로 사용하는 경우에는 ADO를 빈 스레드로 표시하지 마십시오. ADO 레코드 집합의 연결도 끊어야 합니다. 일반적으로 사용자 사이트에서 ADO 구성을 제어할 수 없다면(예를 들어, 고유한 구성을 관리하는 고객에게 웹 응용 프로그램을 판매한 독립적 소프트웨어 공급업체(ISV: independent software vendor)의 경우) 레코드 집합을 캐싱하지 않는 것이 더 좋을 것입니다.
사전 구성 요소도 활발한 개체입니다. LookupTable은 데이터 파일에서 데이터를 로드하며 구성 정보뿐 아니라 콤보 상자 데이터에 유용합니다. Duwamish Books  의 PageCache 개체는 Caprock 사전과 같은 사전 기능을 제공합니다. 이러한 개체 또는 그 파생물은 효과적인 캐싱 정책의 기초를 형성할 수 있습니다. 스크립팅 사전 개체는 활발한 개체가 아니며 응용 프로그램 또는 세션 범위에 저장해서는 안된다는 것을 주의하십시오.
팁 5: 응용 프로그램 또는 세션 개체에서 데이터베이스 연결 캐시 금지
ADO 연결을 캐싱하는 것은 일반적으로 좋지 않은 전략입니다. 응용 프로그램에 하나의 연결 개체가 저장되고 전체 페이지에서 사용된다면 모든 페이지가 이 연결을 사용하려고 경쟁하게 될 것입니다. 연결 개체가 ASP 세션 개체에 저장된 경우에는 모든 사용자를 위해 데이터베이스 연결이 작성될 것입니다. 이것은 연결 풀링의 이익을 상쇄시키며 웹 서버와 데이터베이스에 불필요한 높은 스트레스를 주게 됩니다.
데이터베이스 연결을 캐싱하는 대신 ADO를 사용하는 모든 ASP 페이지에서 ADO 개체를 작성하고 없앱니다. IIS에는 내장된 데이터베이스 연결 풀링이 있기 때문에 이렇게 하는 것이 효과적입니다. 좀더 자세히 말하자면 IIS 는 OLEDB 및 ODBC 연결 풀링을 자동화합니다. 따라서 각 페이지에서 연결을 작성하고 없애는 것이 더 효과적이라는 것을 확인할 수 있습니다.
연결된 레코드 집합은 참조를 데이터베이스 연결에 저장하기 때문에 응용 프로그램 또는 세션 개체에서 연결된 레코드 집합을 캐시하면 안됩니다. 하지만 연결이 끊어진 레코드 집합은 데이터 연결에 대한 참조를 갖지 않기 때문에 안전하게 캐시할 수 있습니다. 레코드 집합의 연결을 끊기 위해서는 다음과 같은 두 단계를 밟아야 합니다.
Set rs = Server.CreateObject("ADODB.RecordSet") rs.CursorLocation = adUseClient ' step 1 ' Populate the recordset with data rs.Open strQuery, strProv ' Now disconnect the recordset from the data provider and data source rs.ActiveConnection = Nothing ' step 2
연결 풀링에 대한 자세한 정보는 ADO 및 SQL 서버 참조에 있습니다.
팁 6: 세션 개체의 현명한 사용
지금 까지 응용 프로그램 및 세션에서 캐싱의 장점을 지지해왔으므로 이제는 세션 개체를 방지하도록 제한하려고 합니다. 앞으로 논의하겠지만 세션을 분주한 사이트에서 사용하면 몇 가지 위험이 있습니다. 분주하다는 것은 일반적으로 초당 수백 페이지가 요청되거나 수천명의 동시 사용자가 있는 사이트를 의미합니다. 이 팁은 전반적으로 측정해야 하는 사이트 즉, 로드를 받아들이거나 내결함성을 구현하기 위한 다중 서버를 사용하는 사이트에 특히 유용합니다. 인트라넷 사이트와 같은 소규모 사이트에서 세션의 편리함은 오버헤드 만큼의 가치가 있습니다.
간단히 말해서 ASP는 자동으로 웹 서버에 접근하는 모든 사용자를 위한 세션을 작성합니다. 각 세션은 약 10 KB의 메모리 오버헤드(세션에 저장된 모든 데이터의 상단에 있는)를 갖고 있어서 모든 요청을 약간 늦춥니다. 세션은 구성할 수 있는 시간 제한 기간동안 유효하며 이 제한 시간은 일반적으로 20분입니다.
세션에 관한 가장 큰 문제는 성능이 아닌 확장성입니다. 세션은 여러 웹 서버들을 걸치지 않기 때문에 일단 하나의 서버에 세션이 만들어지면 그 데이터는 그 서버에 있습니다. 이것은 웹 그룹에서 세션을 사용하면 각 사용자의 요청이 사용자의 세션이 있는 서버로 향하도록 정책을 만들어야 한다는 것을 의미합니다. 이런 것을 사용자를 웹 서버에 "고정"시킨다고 합니다. "고정 세션"이라는 용어는 여기서 유래한 것입니다. 세션이 디스크에 계속 남아있지 않기 때문에 "고정된" 사용자는 웹 서버가 작동을 중지하면 세션 상태를 잃어버리게 됩니다.
고정 세션을 구현하기 위한 정책은 하드웨어 및 소프트웨어 솔루션을 포함합니다. Windows 2000 Advanced Server에 있는 Network Load Balancing  및 Cisco의 Local Director와 같은 솔루션은 약간의 확장성을 희생하여 고정 세션을 구현할 수 있습니다. 이러한 솔루션은 완전하지 않습니다. 이러한 상황에서 자신의 소프트웨어 솔루션을 실행하는 것은 바람직하지 않습니다(우리는 ISAPI 필터 및 URL 맹글링(mangling)과 같은 것을 사용해 왔습니다).
응용 프로그램 개체도 서버를 걸치지 않기 때문에 웹 그룹들 사이에 응용 프로그램 데이터를 공유하거나 업데이트해야 할 경우에는 백 엔드 데이터베이스를 사용해야 합니다. 그러나 읽기 전용 응용 프로그램 데이터를 웹 그룹에서 여전히 사용할 수 있습니다.
작동 시간(장애 조치 및 서버 유지 관리)이 증가는 것 외에 다른 이유가 없다면 대부분 업무용 사이트는 적어도 두 개의 웹 서버에 배포하기를 원합니다. 따라서 업무용 응용 프로그램을 만들 때는 개별적 웹 서버에 사용자 상태를 저장하는 상태 관리 기술뿐 아니라 "고정 세션"을 구현하거나 단순히 세션을 방지해야 합니다.
세션을 사용하지 않는다면 세션을 반드시 꺼야 합니다. Internet Services Manager를 통해 사용자 응용 프로그램의 세션을 끌 수 있습니다.(ISM 설명서 참조) 세션을 사용하려면 몇 가지 방법으로 성능에 영향을 최소화해야 합니다.
세션이 필요하지 않은 컨텐츠(도움말 화면, 방문자 영역 등)를 세션이 꺼진 별도의 ASP 응용 프로그램으로 옮길 수 있습니다. 각 페이지를 기초로 해당 페이지에 세션 개체가 필요 없다는 것을 알리기 위해 다음과 같은 지시어를 ASP 페이지 상단에 놓을 수 있습니다.
<% .EnableSessionState=False %>
이 지시어를 사용하게 되는 이유 중 하나는 세션이 프레임셋과 관심있는 문제를 만드는 것입니다. ASP는 언제나 한번에 한 세션에서 하나의 요청만이 실행되도록 보장합니다. 따라서 브라우저가 한 사용자를 위해 여러 페이지를 요청하면 한번에 단지 하나의 ASP 요청만이 세션에 전달되기 때문에 세션 개체에 액세스할 때 멀티스레딩 문제를 방지합니다. 그러나 불행하게도 프레임셋에 있는 모든 페이지는 동시에 페인트되지 않고 차례로 순차적 방법으로 페인트됩니다. 모든 프레임을 페인트하려면 오래 기다려야 합니다. 이야기의 교훈은 다음과 같습니다. 어떤 프레임셋 페이지가 세션에 의지하지 않는 다면 ASP가 @EnableSessionState=False 지시어를 사용하도록 하십시오.
세션 개체를 사용하지 않고 세션 상태를 관리할 많은 옵션이 있습니다. 상태가 작은 양일 때(4 KB 미만)는 nulls, QueryString 변수 및 숨겨진 형식 변수를 사용하는 것이 바람직합니다. 쇼핑 카드처럼 데이터의 양이 많은 경우는 백 엔드 데이터베이스가 더 적합합니다. 웹 서버 그룹에서 상태 관리 기술에 대해 다룬 많은 글들이 있습니다. 자세한 내용은 세션 상태 참조를 참조하십시오.
팁 7: COM 개체에서 코드 간략화
VBScript 또는 JScript가 많을 때는 이 코드를 컴파일된 COM 개체에 옮겨서 성능을 향상시킬 수 있습니다. 컴파일된 코드는 해석된 코드보다 더 빨리 실행됩니다. 컴파일된 COM 개체는 스크립트가 사용하는 "늦은 바인딩"보다 더 효율적으로 COM 개체 메서드를 불러오는 방법인 "이른 바인딩"을 통해 다른 COM 개체에 액세스할 수 있습니다.
COM 개체에서 코드를 캡슐화하는 것은 여러 가지로 유리합니다.(성능을 제외하고)
  • COM 개체는 프리젠테이션 논리와 비즈니스 논리를 분리하는 데 유용합니다.
  • COM 개체는 코드를 재사용 할 수 있도록 합니다.
  • VB, C++ 또는 Visual J++로 작성된 코드는 ASP로 작성된 것보다 디버그하기 쉽다는 것을 많은 개발자들이 알아냈습니다.
COM 개체는 초기 개발 시간 및 다른 프로그래밍 기술의 필요 등과 같은 단점들이 있습니다. 작은 양의 ASP를 캡슐화하면 성능이 향상되기 보다는 떨어질 수 있습니다. 일반적으로 작은 양의 ASP 코드가 COM 개체로 싸여질 때 성능이 떨어집니다. 이런 경우에는 COM 개체를 작성하고 불러오는 오버헤드가 컴파일된 코드의 이익보다 더 커집니다. ASP 스크립트와 COM 개체를 어떻게 조합해야 최상의 성능이 나오는지는 시행착오를 통해서 알 수 있습니다. Microsoft가 Windows 2000/Windows NT?? 4.0상의 IIS 5.0/IIS 4.0에서 스크립트와 ADO 성능을 상당히 향상시켰다는 것을 참조하십시오. IIS 5.0이 등장하면서 ASP 코드 위에 컴파일된 코드를 사용하여 얻을 수 있었던 성능 향상의 이익이 줄어들었습니다.
ASP에서 COM 개체를 사용하여 얻을 수 있는 이익과 손해에 대한 자세한 논의는 ASP 구성 요소 지침  및 COM과 Microsoft Visual Basic 6.0으로 작성된 분산형 응용 프로그램 프로그래밍  을 참조하십시오. COM 구성 요소를 배포하려면 구성 요소들의 스트레스를 테스트  하는 것이 특히 중요합니다. 사실 모든 ASP 응용 프로그램은 어떤 경우에도 스트레스를 테스트해야 합니다.
팁 8: 늦은 리소스 획득, 이른 해제
이 팁은 간단합니다. 일반적으로 리소스를 늦게 획득해서 일찍 해제하는 것이 가장 바람직합니다. 파일 핸들 및 다른 리소스뿐 아니라 COM 개체에도 해당됩니다.
ADO 연결 및 레코드 집합은 이 최적화에 가장 적합합니다. 레코드 집합을 다 사용한 후 즉, 이 데이터로 테이블을 페인팅했다면 페이지 끝까지 대기하지 말고 즉시 이 데이터를 해제하십시오. VBScript 변수를 Nothing으로 설정하는 것이 가장 좋습니다. 레코드 집합이 단순히 범위를 벗어나게 하지는 마십시오. 관련된 명령 및 연결 개체를 모두 해제하십시오.(레코드 집합에서 Close()를 호출하거나 레코드 집합을 Nothing으로 설정하기 전의 연결을 호출하는 것을 잊지 마십시오) 이렇게 하면 데이터베이스가 리소스를 다루는 시간을 줄여주며 가능한 빨리 데이터베이스 연결을 연결 풀로 해제합니다.
팁 9: 안정성과 성능을 교환하는 종속 프로세스 실행
ASP와 MTS/COM+에는 모두 안정성과 성능을 교환할 수 있는 구성 옵션이 있습니다. 응용 프로그램을 만들거나 배포할 때는 이러한 교환을 이해해야 합니다.

ASP 옵션

ASP 응용 프로그램은 세가지 중 한가지 방법으로 실행되도록 구성할 수 있습니다. IIS 5.0에는 이러한 옵션을 설명하기 위해 "격리 수준"이라는 용어를 도입했습니다. 낮음보통높음의 세가지 격리 수준 값이 있습니다.
  • 낮은 격리. 이것은 모든 IIS 버전에서 지원되며 가장 빠릅니다. 이것은 주요 IIS 프로세스인 Inetinfo.exe에서 ASP를 실행합니다. ASP 응용 프로그램이 작동을 중지하면 IIS도 작동을 중지합니다.(IIS 4.0에서 IIS를 다시 시작하기 위해 웹 마스터는 InetMon과 같은 도구를 사용하여 사이트를 모니터하고 실패한 서버를 다시 시작하기 위해 배치 파일을 실행시킵니다. IIS 5.0에는 안정적인 재시작  이 도입되어 실패한 서버를 자동으로 다시 시작합니다.)
  • 보통 격리. ASP가 IIS 프로세스 밖에서 실행하기 때문에 독립 프로세스라고 하는 새로운 수준을 IIS 5.0에 도입했습니다. 보통 격리에서는 보통으로 실행하도록 구성된 모든 ASP 응용 프로그램이 단 하나의 프로세스 공간을 공유합니다. 이렇게 하면 하나의 상자에서 여러 개의 독립 프로세스 ASP 응용 프로그램을 실행하는 데 필요한 프로세스의 수를 줄일 수 있습니다. 보통은 IIS 5.0에서 기본 격리 수준입니다.
  • 높은 격리. IIS 4.0과 IIS 5.0에서 지원되는 높은 격리도 독립 프로세스입니다. ASP이 작동을 중지해도 웹 서버는 계속 작동합니다. ASP 응용 프로그램은 자동으로 다음 ASP 요청을 다시 시작합니다. 높은 격리를 사용하면 High로 실행하도록 구성된 각 ASP 응용 프로그램은 각자 고유한 공간에서 실행합니다. 이렇게 하면 ASP 응용 프로그램을 다른 ASP 응용 프로그램으로부터 보호합니다. 이 것의 단점은 각 ASP 응용 프로그램에 대해 개별적인 프로세스를 해야 한다는 것입니다. 하나의 상자에 십여 개의 응용 프로그램을 호스트해야 할 때 오버헤드가 많이 추가될 수 있습니다.
어떤 옵션이 가장 최선일까요? IIS 4.0에서는 독립 프로세스를 실행하면 성능이 급격히 떨어졌습니다. IIS 5.0에서는 독립 프로세스 ASP 응용 프로그램을 실행하는 비용을 최소화하기 위해 많은 작업을 해야 했습니다. 사실 대부분 테스트에서 IIS 5.0에서의 독립 프로세스 ASP 응용 프로그램이 IIS 4.0에서의 종속 프로세스 응용 프로그램보다 빨리 실행했습니다. 하지만 여전히 두 플랫폼 모두에서 종속 프로세스(낮은 격리 수준)가 최고의 성능을 발휘하고 있습니다. 그러나 상대적으로 적중률이 낮거나 최대 처리량이 낮은 경우 낮은 격리 수준을 사용하는 것은 별로 유리하지 않습니다. 따라서 각 웹 서버에 초당 수백 또는 수천 페이지가 필요하지 않다면 낮은 격리 수준을 사용하고 싶지 않을 것입니다. 언제나 처럼 여러 구성으로 테스트를 한 다음 어떤 교환을 할지를 정하십시오.
참고: 독립 프로세스(보통 또는 높은 격리) ASP 응용 프로그램을 실행할 때 이 응용 프로그램은 NT4에 있는 MTS 및 Windows 2000에 있는 COM+에서 실행됩니다. 즉, NT4에서는 Mtx.exe에서 실행되고 Windows 2000에서는 DllHost.exe에서 실행됩니다. 이러한 프로세스가 작업 관리자에서 실행되는 것을 알 수 있습니다. 또한 독립 프로세스 ASP 응용 프로그램을 위해 IIS가 MTS 패키지 또는 COM+ 응용 프로그램을 구성하는 방법도 알 수 있습니다.

COM 옵션

비록 ASP 옵션과 완전히 일치하지는 않지만 COM 구성 요소도 세 개의 구성 옵션을 갖고 있습니다. COM 구성 요소는 구성되지 않거나, 라이브러리 응용 프로그램으로 구성되거나, 서버 응용 프로그램으로 구성될 수 있습니다. 구성되지 않는다는 것은 구성 요소가 COM+과 함께 등록되지 않는다는 의미입니다. 구성 요소는 호출자의 프로세스 공간에서 실행될 것입니다. 즉, 종속 프로세스입니다. 라이브러리 응용 프로그램도 종속 프로세스지만 보안, 트랜잭션 및 컨텍스트 지원과 같은 COM+의 혜택을 받습니다. 서버 응용 프로그램은 그들만의 프로세스 공간에서 실행하도록 구성됩니다.
라이브러리 응용 프로그램보다 구성되지 않은 구성 요소가 약간 유리하다는 것을 알 수 있을 것입니다. 또한 서버 응용 프로그램보다 라이브러리 응용 프로그램은 매우 큰 성능의 이익이 있다는 것을 알 수 있을 것입니다. 이것은 라이브러리 응용 프로그램은 ASP와 같은 프로세스에서 실행하지만 서버 응용 프로그램은 그들 고유의 프로세스에서 실행하기 때문입니다. 프로세스간 호출은 종속 프로세스보다 비용이 많이 듭니다. 또한 프로세스간에 레코드 집합과 같은 데이터를 전달할 때 모든 데이터를 두 프로세서 사이에서 복사해야 합니다.
위험! COM 서버 응용 프로그램을 사용할 때 ASP와 COM간에 개체를 전달하려면 개체가 "marshal-by-value" 즉 MBV를 구현하는지 확인해야 합니다. MBV를 구현하는 개체는 한 프로세스에서 다른 프로세스로 자신을 복사합니다. 이것은 개체가 작성자의 프로세스에 남아있고 다른 프로세스가 이 개체를 사용하기 위해 반복적으로 작성하는 프로세스를 호출하는 다른 방법보다 효율적입니다. 연결이 끊어진 ADO 레코드 집합은 marshal-by-value를 구현하지만 연결된 레코드 집합은 그렇지 않습니다. Scripting.Dictionary는 MBV를 구현하지 않으면 프로세스간에 전달되면 안됩니다. 마지막으로 VB 프로그래머에게 보내는 메시지입니다. 매개 변수 ByVal을 전달하여 MBV를 구현할 수 없습니다. MBV는 원래 구성 요소 작성자만이 구현할 수 있습니다.

무엇을 해야 합니까?

성능과 안정성을 합리적으로 교환하는 구성을 추천한다면 다음과 같습니다.
  • IIS 4.0에서, ASP의 낮은 격리 수준과 MTS 서버 패키지를 사용하십시오.
  • IIS 5.0에서, ASP의 보통 격리 수준과 COM+ 라이브러리 응용 프로그램을 사용하십시오.
이것은 매우 일반적인 지침입니다. 호스팅 회사는 일반적으로 보통 또는 높은 격리 수준에서 ASP를 실행하지만 단일 목적 웹 서버는 낮은 격리 수준에서 실행할 수 있습니다. 교환을 측정하고 어떤 구성이 가장 적합한지 스스로 결정하십시오.
팁 10: Option Explicit 사용
.asp 파일에서 Option Explicit을 사용하십시오. .asp 파일의 상단에 위치하는 이 지시어는 개발자가 사용할 모든 변수를 선언하도록 합니다. 이렇게 하면 변수를 잘 못 입력하거나 불필요한 새 변수를 만드는 것을 방지할 수 있기 때문에(예를 들어, MyXMLStirng=대신MyXLMString=…) 많은 프로그래머가 응용 프로그램을 디버깅할 때 유용하다고 생각합니다.
아마 선언된 변수가 선언되지 않은 변수보다 빠르다는 것을 알아낸 것이 더 중요할 수도 있습니다. 보이지 않는 상태에서 스크립팅 실행 시간은 선언되지않은 변수를 사용할 때 마다 이 변수를 이름으로 참조합니다. 반면 선언된 변수는 컴파일 시간 또는 실행 시간에 서수로 지정됩니다. 그 다음 선언된 변수는 이 서수에 의해 참조됩니다. Option Explicit은 반드시 변수 선언을 하도록 하기 때문에 모든 변수가 선언되고 빨리 액세스할 수 있습니다.
팁 11: 서브루틴 및 함수에서 지역 변수 사용
지역 변수는 서브루틴 및 함수에서 선언된 변수입니다. 함수 또는 서브루틴안에서 지역 변수 액세스는 전역 변수 액세스보다 빠릅니다. 또한 지역 변수를 사용하면 코드가 더 깔끔하기 때문에 가능하면 지역 변수를 사용하는 것이 좋습니다.
팁 12: 자주 사용되는 데이터를 스크립트 변수로 복사
ASP에서 COM 개체에 액세스할 때는 자주 사용되는 개체 데이터를 스크립트 변수에 복사해야 합니다. 이렇게 하면 스크립트 변수에 액세스하는 것과 비교했을 때 상대적으로 비용이 많이 드는 COM 메서드 호출을 줄여줍니다. Collection 및 Dictionary 개체에 액세스할 때도 이 기술이 비용이 많이 드는 조회를 줄여줍니다.
일반적으로 한번 이상 개체 데이터에 액세스하려면 이 데이터를 스크립트 변수에 복사합니다. 이렇게 해서 가장 최적화되는 것은 요청 변수입니다.(Form 및 QueryString 변수) 예를 들어, 사용자의 사이트가 UserID로 불리는 QueryString 변수를 전달할 때 이 UserID가 특정 페이지에서 12번 참조된다고 가정해 보십시오. 요청("UserID")을 12번 호출하는 대신 UserID를 ASP 페이지 상단에서 변수로 지정하고 이 페이지에서 이 변수를 사용하면 11번의 COM 메서드 호출을 절약할 수 있습니다.
실제로 COM 속성 또는 메서드에 액세스하는 것은 비용이 너무 많이 듭니다. 매우 일반적인 코드를 보여주는 예제가 있습니다.
Foo.bar.blah.baz = Foo.bar.blah.qaz(1)If Foo.bar.blah.zaq = Foo.bar.blah.abc Then ' ...
이 코드는 다음과 같이 실행됩니다.
  1. 변수 Foo는 전역 개체로 확인됩니다.
  2. 변수 bar는 Foo의 구성원으로 확인됩니다. 이것은 COM 메서드 호출이 됩니다.
  3. 변수 blah는 Foo.bar의 구성원으로 확인됩니다. 이것 역시 COM 메서드 호출이 됩니다.
  4. 변수 qaz는 foo.bar.blah의 구성원으로 확인됩니다. 물론 COM 메서드 호출이 됩니다.
  5. Foo.bar.blah.quaz(1)를 불러옵니다. 또 하나의 COM 메서드 호출입니다. 그림을 이해하시겠습니까?
  6. baz를 확인하기 위해 1-3 단계를 다시 합니다. 이 시스템은 qaz 호출이 개체 모델을 변경한 것을 모르기 때문에 baz를 확인하려면 1-3 단계를 다시 해야 합니다.
  7. baz를 Foo.bar.blah의 구성원으로 확인합니다. 속성을 입력합니다.
  8. . 1-3 단계를 다시 실행하고 zaq를 확인합니다.
  9. 1-3 단계를 다시 실행하고 abc를 확인합니다.
여기서 알 수 있듯이 이것은 매우 비효율적입니다. VBScript에서 이 코드를 작성하는 더 빠른 방법은 다음과 같습니다.
Set myobj = Foo.bar.blah ' do the resolution of blah ONCEMyobj.baz = myobj.qaz(1)If Myobj.zaq = Myobj.abc Then '...
VBScript 5.0 이상을 사용하는 경우 With문을 사용하여 이것을 작성할 수 있습니다.
With Foo.bar.blah .baz = .qaz(1) If .zaq = .abc Then '... ...End With
이 팁은 VB 프로그래밍에서도 작동한다는 것을 참조하십시오.
팁 13: 배열 재정의 방지
배열을 재정의하지 않도록 하십시오. 물리적인 메모리 크기에 제약이 있는 컴퓨터를 사용하는 경우 성능에 관한한 최악의 경우에 배열의 초기 정의를 설정하는 것이 가장 좋습니다. 그렇지 않으면 정의를 가장 적합하게 설정하고 필요한 경우에는 재정의합니다. 이것은 불필요한 몇 MB의 메모리를 직접 할당해야 한다는 것을 의미하지는 않습니다.
다름 코드는 정의 및 재정의의 불필요한 사용을 보여줍니다.
<% Dim MyArray()Redim MyArray(2)MyArray(0) = "hello"MyArray(1) = "good-bye"MyArray(2) = "farewell"...' some other code where you end up needing more space happens, then ...Redim Preserve MyArray(5)MyArray(3) = "more stuff"MyArray(4) = "even more stuff"MyArray(5) = "yet more stuff"%>
배열을 확장하기 위해 재정의하는 것보다는 처음에 정확한 사이즈(이 경우에는 5)로 배열을 정의하는 것이 훨씬 바람직합니다. 약간의 메모리가 낭비될 수 있지만(모든 요소의 사용을 중단하지 않으면) 속도가 빨라집니다.
팁 14: 응답 버퍼링 사용
"응답 버퍼링"을 켜면 전체 한 페이지 정도의 출력을 버퍼할 수 있습니다. 이렇게 하면 브라우저에 쓰는 양을 최소화하여 전체적으로 성능이 향상됩니다. 각 쓰기에는 많은 오버헤드(회선으로 가는 데이터의 양 및 IIS에)가 있기 때문에 쓰기가 적을수록 바람직합니다. TCP/IP는시작이 느리고 Nagling  알고리즘(네트워크 정체를 최소화하는 데 사용)을 사용하기 때문에 작은 블록을 여러 개 전송하는 것 보다는 데이터의 큰 블록을 몇 개 전송하는 것이 더 효율적입니다.
응답 버퍼링을 켜는 방법은 두 가지가 있습니다. 첫째, Internet Services Manager를 사용하여 전체 응용 프로그램에 응답 버퍼링을 켤 수 있습니다. 이것은 바람직한 접근법이며 IIS 4.0 및 IIS 5.0에 있는 새로운 ASP 응용 프로그램을 위해 초기값으로 응답 버퍼링이 켜집니다. 두번째는 페이지 단위를 기초로 한 것으로서 ASP 페이지의 상단에 다음과 같은 코드 줄을 넣어 응답 버퍼링을 사용할 수 있습니다.
<% Response.Buffer = True %>
이 코드 줄은 브라우저에 응답 데이터를 쓰기 전에 실행해야 합니다.(즉, ASP 스크립트에 HTML이 나타나기 전 및 Response nulls 컬렉션을 사용하여 nulls가 설정되기 전에) 일반적으로 전체 응용 프로그램에 응답 버퍼링을 켜놓는 것이 가장 좋습니다. 이렇게 하면 모든 페이지에 위의 코드 줄을 넣지 않아도 됩니다.

Response.Flush

응답 버퍼링에 대한 한가지 공통적인 불만은 전체 페이지가 생성될 때까지 기다려야 무언가를 볼 수 있기 때문에 사용자는 ASP 페이지의 응답 시간이 느리다고 느끼는 것입니다.(전체 응답 시간이 향상되었음에도 불구하고) 오래 걸리는 페이지에서는 Response.Buffer = False를 설정하여 응답 버퍼링을 끌 수 있습니다. 하지만 이것 보다는 Response.Flush 메서드를 사용하는 것이 더 훌륭한 전략입니다. 이 메서드는 ASP가 브라우저로 페인트한 모든 HTML을 플러시합니다. 예를 들어, 천 개의 행(row)이 있는 테이블 중 백 개 행을 페인트한 다음 ASP는 페인트한 결과를 브라우저로 보내기 위해 Response.Flush를 호출할 수 있습니다. 이렇게 하면 나머지 행이 준비되기 전에 사용자는 우선 백 개 행을 볼 수 있습니다. 이러한 기술은 데이터를 브라우저로 점차적으로 프리젠테이션하는 것과 결합된 응답 버퍼링을 제공합니다.
(위의 행이 천 개인 테이블의 예에서 많은 브라우저는 닫는 태그가 나타나야만 테이블을 페인팅한다는 것을 참조하십시오. 대상 브라우저가 이것을 지원하는지 확인하십시오. 이렇게 하려면 테이블을 행을 적게 갖는 여러 개의 테이블로 나눈 다음 각 테이블 다음에Response.Flush를 호출해 보십시오. 새로운 Internet Exploer 버전은 테이블을 완전히 다운로드하기 전에 테이블을 페인트하며 테이블의 열(column)의 폭을 지정하면 특히 빨리 페인트합니다. 이렇게 하면 Internet Explorer가 모든 셀의 컨텐츠 폭을 측정하여 열의 폭을 계산하지 않도록 도와줍니다.)
응답 버퍼링에 대한 또 하나의 불만은 큰 페이지를 생성할 때 서버 메모리를 많이 사용한다는 것입니다. 큰 페이지를 생성하는 지혜는 제외하고 이 문제는 Response.Flush를 신중히 사용하여 해결할 수 있습니다.
팁 15: 일괄 처리 인라인 스크립트 및 Response.Write 문
VBScript 구문 <% = expression %>은 "expression"의 값을 ASP 출력 스트림에 씁니다. 응답 버퍼링을 켜지 않으면 이 문(statement)이 여러 작은 패킷으로 네트워크를 통해 브라우저로 데이터를 쓰게 됩니다. 이 과정은 매우 느립니다. 작은 양의 스크립트 및 HTML을 여기 저기 배치하면 스크립트 엔진과 HTML간의 전환이 일어나서 성능이 떨어집니다. 그러므로 다음과 같은 팁을 사용하십시오. 가깝게 모여있는 인라인 식(expression)을 Response.Write를 한 번 호출하는 것으로 교체합니다. 예를 들어 다음의 예제처럼 행의 필드마다 응답 스트림에 쓰기가 하나 있고 행마다 VBScript 및 HTML 사이에 많은 스위치가 있습니다.
<% For Each fld in rs.Fields %> <%Next While Not rs.EOF%> <% For Each fld in rs.Fields %> <% Next <% rs.MoveNext Wend %>
<% = fld.Name %>
<% = fld.Value %>
아래에 있는 더 효율적인 코드는 행마다 응답 스트림에 쓰기가 하나 있습니다. 모든 코드는 하나의 VBScript 블록에 포함됩니다.
<% For each fld in rs.Fields Response.Write ("" & vbCrLf) Next While Not rs.EOF Response.Write ("") For Each fld in rs.Fields %>Response.Write("" & vbCrLf) Next Response.Write "" Wend%>
" & fld.Name & "
" & fld.Value & "
이 팁은 응답 버퍼링을 사용할 수 없을 때 더 큰 효과가 있습니다. 응답 버퍼링을 사용하는 것이 가장 바람직 하며 그런 다음Response.Write를 일괄 처리하면 성능이 향상되는지 살펴 봅니다.
(이 특정 예제에서 테이블의 본문을 작성하는 중첩 루프(While Not rs.EOF)는 GetString  를 신중하게 호출하여 교체할 수 있습니다.)
팁 16: 긴 이동을 시작하기 전에 Response.IsClientConnected 사용
인내심이 부족한 사용자는 요청을 실행하기도 전에 ASP 페이지를 중단할 수 있습니다. 사용자가 Refresh를 누르거나 서버에 있는 다른 페이지로 이동하면 ASP 요청 대기열의 끝에 새로운 요청이 놓이고 연결이 끊어진 요청은 대기열의 가운데 놓입니다. 서버에 로드가 높을 때(요청 대기열이 길고 따라서 응답 시간도 길어집니다.) 이런 상황이 발생하며 이것은 상황을 더욱 악화시킵니다. 사용자가 더 이상 연결되어있지 않으면 ASP 페이지를 실행할 수 없습니다.(특히 느리고 큰 ASP 페이지) Response.IsClientConnected 속성을 사용하여 이러한 상태를 확인할 수 있습니다. 이것이 False를 반환하면 Response.End를 호출하고 나머지 페이지를 중지해야 합니다. 사실 IIS 5.0은 이러한 것을 모두 집대성합니다. ASP가 새로운 요청을 실행하려고 할 때마다 그 요청이 대기열에서 얼마나 오래 있었는지를 알기 위해 확인합니다. 이 요청이 대기열에 3초 이상 있었다면 ASP는 클라이언트가 여전히 연결되어 있는지 확인한 다음 연결되어 있지 않을 때는 즉시 요청을 종료합니다. 이 3초 제한 시간을 조정하려면 메타베이스에서 AspQueueConnectionTestTime 설정을 사용할 수 있습니다.
실행 시간이 매우 긴 페이지가 있다면 중간에 Response.IsClientConnected를 확인하고 싶을 수도 있습니다. 응답 버퍼링을 사용하고 있다면 사용자에게 무언가가 진행중이라는 것을 알리기 위해 중간에 Response.Flush를 사용하는 것도 좋습니다.
참고 IIS 4.0에서는 우선 Response.Write를 실행하지 않으면 Response.IsClientConnected가 정확하게 실행되지 않습니다. 버퍼링을 사용하고 있다면 Response.Flush를 사용해야 합니다. IIS 5.0에서는 이렇게 하지 않아도 Response.IsClientConnected가 잘 작동합니다. 어떤 경우에나 Response.IsClientConnected는 약간의 비용이 들기 때문에 적어도 500 밀리초(초당 12 페이지의 처리량을 유지하려면 이것도 긴 시간입니다.)가 소요되는 작업 앞에만 사용해야 합니다. 일반적인 경험에 따라 테이블의 행(row)을 페인팅할 때와 같이 복잡한 루프의 모든 반복에 호출하지 마십시오. 대신 테이블의 20번째 또는 50번째 행에서 호출하십시오.
팁 17: 태그를 사용한 개체 인스턴스화
모든 코드 경로에서 사용되지 않는 개체를 참조해야 한다면(특히 서버 혹은 응용 프로그램 범위 개체) Server.CreateObject 메서드를 사용하기 보다는 Global.asa에서 태그를 사용하여 개체를 선언하십시오. Server.CreateObject는 즉시 개체를 만듭니다. 이 개체를 나중에 사용하지 않는다면 결국 리소스를 낭비하는 것입니다. 태그는 objname을 선언하지만 이 개체의 메서드 또는 속성 중 하나가 처음 사용될 때까지 objname은 실제로 만들어지지 않습니다.
이것은 지연 평가의 또 다른 예입니다.
팁 18: ADO 및 다른 구성 요소를 위한 TypeLib 선언 사용
ADO를 사용할 때 개발자는 ADO의 다양한 상수에 액세스하기 위한 adovbs.txt를 포함합니다. 이 파일은 상수를 사용할 모든 페이지에 포함되어야 합니다. 이 상수 파일은 매우 커서 모든 ASP 페이지의 컴파일 시간 및 스크립트 크기에 상당한 오버헤드를 추가합니다.
IIS 5.0은 구성 요소의 형식 라이브러리에 바인딩하는 기능을 도입했습니다. 이 기능을 사용하면 형식 라이브러리를 한번 참조하여 이것을 모든 ASP 페이지에 사용할 수 있습니다. 각 페이지는 상수 파일을 컴파일할 필요가 없기 때문에 구성 요소 개발자는 ASP에서 사용할 VBScript #include 파일을 작성하지 않아도 됩니다.
ADO TypeLib를 액세스하려면 다음 문(statement) 중 하나를 Global.asa에 포함해야 합니다.
또는
팁 19: 사용자 브라우저의 유효성 검사 기능 이용
최신 브라우저는 XMLDHTMLJava  애플릿 및 원격 데이터 서비스  (Remote Data Service)와 같은 기능을 지원을 개발해왔습니다. 이러한 기능을 최대한 이용하십시오. 이러한 기술을 사용하면 데이터 캐싱뿐 아니라 클라이언트 쪽 유효성 검사를 실행하여 웹 서버로의 왕복 이동을 줄일 수 있습니다. 스마트 브라우저를 사용하면 브라우저가 사용자를 위해 약간의 유효성 검사를 할 수 있습니다.(예를 들어, POST를 실행하기 전에 신용 카드가 해당 금액을 사용할 수 있는지  확인할 수 있습니다.) 다시 강조하지만 이 기능을 가능한 많이 이용하십시오. 클라이언트 쪽 왕복 이동을 줄이기 때문에 서버가 액세스하는 백 엔드 리소스뿐 아니라 네트워크 소통량(비록 브라우저로 보내지는 초기 페이지가 더 크더라도)과 웹 서버의 스트레스를 줄일 수 있습니다. 게다가 사용자는 새로운 페이지를 자주 반입할 필요가 없기 때문에 경험이 향상됩니다. 하지만 이것은 서버 쪽 유효성 검사까지 해주지 않기 때문에 서버쪽 유효성 검사하는 것을 잊지 마십시오. 이것은 브라우저가 클라이언트쪽 유효성 검사 루틴을 실행하지 않거나 해킹과 같은 이유로 잘못된 데이터가 클라이언트에서 오는 것을 방지합니다.
대부분은 "브라우저 독립적" HTML을 작성하여 만들어졌습니다. 이것은 성능을 향상시키는 기능이 있는 일반적인 브라우저를 개발자가 이용할 수 없도록 합니다. 매우 성능이 높은 사이트는 반드시 브라우저 "범위"를 언급해야 하며 일반적인 브라우저를 위해 페이지를 최적화하는 것이 바람직합니다. 브라우저 기능 구성 요소(Browser Capabilities Component)를 사용하여 ASP에서 브라우저 기능을 쉽게 검색할 수 있습니다. Microsoft FrontPage와 같은 도구는 사용자가 대상으로 선택한 브라우저 및 HTML 버전에서 실행되는 코드를 설계할 수 있도록 도와줍니다. 자세한 내용은 When is Better Worse? Weighing the Technology Trade-Offs  를 참조하십시오.
팁 20: 루프에서 문자열 연결 방지
많은 사람들이 다음과 같이 루프 안에 문자열을 작성합니다.
s = " " & vbCrLfFor Each fld in rs.Fields s = s & " "NextWhile Not rs.EOF s = s & vbCrLf & " " For Each fld in rs.Fields s = s & " " Next s = s & " " rs.MoveNextWends = s & vbCrLf & "
" & fld.Name & "
" & fld.Value & "
" & vbCrLfResponse.Write s
이러한 접근에는 몇 가지 문제가 있습니다. 우선 반복적으로 문자열을 연결하면 시간이 제곱으로 걸립니다. 다시 말해 루프를 실행하는 데 걸리는 시간은 레코드 수와 필드 수를 곱한 값의 제곱에 비례합니다. 간단한 예제가 이것을 더욱 명확하게 합니다.
s = ""For i = Asc("A") to Asc("Z") s = s & Chr(i)Next
첫번째 반복에서 하나의 문자로된 문자열 "A"을 얻습니다. 두번째 반복에서 VBScript는 문자열을 재할당하고 두 문자("AB")를 s로 복사해야 합니다. 세번째 반복에서 VBScript는 s를 다시 재할당하고 3개 문자를 s로 복사합니다. N번째(26번째) 반복에서 s를 재할당하고 N개 문자를 s로 복사합니다. 이것이 N*(N+1)/2 복사본이 있는 1+2+3+…+N의 합계입니다.
위의 레코드 집합 예제에서 100개 레코드와 5개 필드가 있다면 내부 루프는 100*5 = 500번 실행되고 모든 복사와 재할당을 하는 데 걸린 시간은 500*500 = 250,000에 비례할 것입니다. 이것이 적절한 크기의 레코드 집합을 위한 복사입니다.
이 예제에서 문자열 연결을 Response.Write() 또는 인라인 스크립트(<% = fld.Value %>)와 교체하여 코드를 향상시킬 수 있습니다. 응답 버퍼링이 켜있다면(켜있어야 함) Response.Write는 응답 버퍼의 끝에 데이터를 추가할 뿐이기 때문에 교체하는 것이 빠릅니다. 재할당이 포함되지않기 때문에 매우 효과적입니다.
ADO 레코드 집합을 HTML 테이블로 변환하는 특별한 경우에는 GetRows 또는 GetString  을 사용하도록 하십시오.
JScript에서 문자열을 연결하는 경우 += 연산자를 사용하는 것이 바람직합니다. 예를 들어 s = s + "some string"이 아닌 s += "some string"을 사용하십시오.
팁 21: 브라우저 및 프록시 캐싱 사용
ASP는 브라우저와 프록시에서 기본으로 캐싱을 사용하지 않습니다. 잠재적으로 시간에 민감한 정보를 가지고있는 ASP 페이지는 본질적으로 동적이기 때문에 이해할 수 있는 부분입니다. 모든 뷰에서 새로 고침이 필요 없는 페이지의 경우 브라우저와 프록시 캐싱을 사용해야 합니다. 이를 통해 브라우저와 프록시는 일정 길이의 시간동안 페이지의 "캐시된" 복사본을 사용할 수 있으며 사용자가 이를 제어할 수 있습니다. 캐싱은 서버의 부하를 크게 줄일 수 있으며 사용자의 이용도를 향상시킬 수 있습니다.
어떤 종류의 동적 페이지에 캐싱을 사용할까요? 밑에 몇 가지 예를 나타내었습니다.
  • 날씨가 매 5분 마다 업데이트되는 일기예보 페이지.
  • 하루에 두 번 업데이트되는 뉴스 또는 출판물을 게시하는 홈 페이지.
  • 근간이 되는 통계를 몇 시간마다 업데이트하는 뮤츄얼 펀드 성과 목록.
브라우저와 프록시의 캐싱을 사용하면 웹 페이지에 기록되는 방문자수가 줄어들게 됩니다. 모든 페이지 뷰를 정확하게 측정하거나 광고를 게시하려는 경우에는 브라우저와 프록시의 캐싱이 실망스러울 것입니다.
브라우저 캐싱은 웹 서버에서 브라우저로 보내는 HTTP "Expires" 헤더로 제어합니다. ASP는 두 가지 간단한 메커니즘을 제공하여 이 헤더를 보냅니다. 몇 분 후에 페이지가 만료되도록 설정하려면 Response.Expires 속성을 설정하십시오. 다음 예는 브라우저가 컨텐츠를 10분 후에 만료하도록 지시합니다.
<% Response.Expires = 10 %>
Response.Expires를 음수 또는 0으로 설정하면 캐싱을 사용할 수 없게 됩니다. -1000(하루가 약간 넘음)과 같이 큰 음수를 사용하여 서버와 브라우저 클럭 사이의 불일치를 해결하십시오. 두 번째 속성인 Response.ExpiresAbsolute를 사용하면 컨텐츠가 만료되는 특정 시간을 설정할 수 있습니다.
<% Response.ExpiresAbsolute = #May 31,2001 13:30:15# %>
만료 설정을 위해 Response 개체를 사용하는 것 외에 일반적으로 HTML 파일의 섹션 내에 태그를 작성할 수도 있습니다. 프록시는 아닐지라도 일부 브라우저는 이 지시에 따라 작동합니다.
마지막으로, Response.CacheControl 속성을 사용하여 HTTP 프록시가 캐시하기에 컨텐츠가 유효한지의 여부를 나타낼 수 있습니다. 이 속성을 "Public"으로 설정하면 프록시가 컨텐츠를 캐시할 수 있게 됩니다.
<% Response.CacheControl = "Public" %>
이 속성은 "Private"이 기본으로 설정되어 있습니다. 어떤 사용자에 특정한 데이터를 보여주는 페이지에 대해서는 프록시 캐싱을 사용하지 않아야 합니다. 캐싱을 설정하면 프록시는 어떤 사용자 소유의 페이지를 다른 사용자에게 제공하기 때문입니다.
팁 22: 가능한 한 Response.Redirect 대신 Server.Transfer 사
Response.Redirect는 브라우저가 다른 페이지를 요청하도록 지시합니다. 이 기능을 종종 사용하여 사용자를 로그온 또는 오류 페이지로 다시 연결시킵니다. 다시 연결되면 새 페이지 요청이 강제되기 때문에 결과적으로 브라우저는 웹 서버에 두 번 왕복해야 하며 웹 서버는 추가 요청을 처리해야 합니다. IIS 5.0은 동일 서버상에서 다른 ASP 페이지로 실행을 전달하는Server.Transfer라는 새 기능을 도입합니다. 이 기능으로 브라우저와 웹 서버 간의 불필요한 왕복을 피할 수 있기 때문에 결과적으로 전체 시스템이 향상될 뿐만 아니라 사용자에게는 빠른 반응 시간을 제공하게 됩니다. Server.Transfer 및 Server.Execute에 관한 내용이 있는 New Direction in Redirection  을 살펴보십시오.
IIS 5.0 및 ASP 3.0의 새 기능을 전부 수록한 IIS 5.0에서 ASP 이용  도 참조하십시오.
팁 23: 디렉터리 URL에서 후행 슬래시 사용
관련 팁은 디렉터리를 가리키는 URL에서 후행 슬래시(/)를 사용하는 것입니다. 후행 슬래시를 생략하면 브라우저는 서버에 요청하여 디렉터리를 요구하고 있다는 응답을 받습니다. 그러면 브라우저는 URL에 슬래시를 첨가하여 두번째 요청을 하며 이때서야 서버가 그 디렉터리(또는 기본 문서가 없거나 디렉터리 브라우징을 사용할 수 없는 경우 디렉터리 목록)에 대한 기본 문서로 응답합니다. 슬래시의 첨가는 처음의 쓸데없는 왕복을 제거합니다. 편리한 사용을 위해서는 표시 이름에 후행 슬래시를 생략하고 싶을 것입니다.
예를 들어, 다음을 작성하십시오.
http://msdn.microsoft.com/workshop
이것은 웹 사이트에서 홈페이지를 가리키는 URL에도 적용됩니다. 이 아니라 을 사용하십시오.
팁 24: 서버 변수의 사용을 피함
서버 변수에 액세스하면 웹 사이트가 서버에 특별한 요청을 하게 되어 요청한 것만이 아니라 모든 서버 변수를 수집하게 됩니다. 곰팡이 쓴 다락방에 있는 폴더의 특정 물건을 가져와야 하는 것과 같습니다. 그 하나의 물건을 원하는 경우, 그 물건에 액세스하기 전에 우선 다락방에 가서 폴더를 찾아야 합니다. 서버 변수를 요청할 때도 마찬가지입니다. -performance hit은 서버 변수를 처음 요청할 때 발생합니다. 다른 서버 변수에 대한 계속된 요청은 performance hit을 유발하지 않습니다.
비한정 Request 개체(예, Request("Data"))에 절대 액세스하지 마십시오. Request.nullsRequest.FormRequest.QueryString 또는Request.ClientCertificate에 있지 않은 항목의 경우, Request.ServerVariables에 대한 암시적 호출이 있습니다.Request.ServerVariables 집합은 다른 집합보다 훨씬 느립니다.
팁 25: 최신 및 최고급으로 업그레이드.
시스템 구성 요소는 일정하며 최신 및 최고급으로 업그레이드하는 것이 좋습니다. Windows 2000  (및 그에 따른 IIS 5.0, ADO 2.5, MSXML 2.5, Internet Explorer 5.0, VBScript 5.1및 JScript 5.1)으로 업그레이드하는 것이 가장 바람직합니다. IIS 5.0 및 ADO 2.5은 다중 프로세서 컴퓨터에서 극적인 성능 향상을 수행합니다. Windows 2000에서 ASP 는 4개 이상의 프로세서로 훌륭하게 확장하며 반면 IIS 4.0에서는 ASP가 두 프로세서 이상으로 잘 확장되지 않습니다. Windows 2000으로 업그레이드한 후 응용 프로그램에서 스크립트 코드와 ADO를 많이 사용하면 할 수록 더욱 큰 성능 향상을 보게 될 것입니다.
Windows 2000으로 업그레이드할 수 없는 경우에는 최신 버전의 SQL Server  , ADO  , VBScript 및 JScript  , MSXMLInternet Explorer  그리고 NT4 Service Pack으로 업그레이드할 수 있습니다. 이 모두가 성능을 향상시킬 뿐 아니라 신뢰도도 높입니다.
팁 26: 웹 서버 조정.
사이트 성능을 향상시킬 수 있는 몇 가지 IIS 튜닝 매개 변수가 있습니다. 예를 들면, IIS 4.0의 경우 ASP ProcessorThreadMax 매개 변수(IIS 문서 참조)를 증가시켜서 상당한 이득을 얻는 경우가 종종 있습니다. 데이터베이스 또는 화면 스크레퍼와 같은 다른 미들웨어 제품과 같은 백 엔드 리소스를 기다리는 경향이 있는 사이트에서는 특히 큰 이득을 얻습니다. IIS 5.0의 경우 ASP Thread Gating을 사용하는 것이AspProcessorThreadMax에 대한 최적 설정을 찾는 것보다 더 효과적입니다..
아래 Tuning IIS 튜닝을 참조하십시오
최적 구성 설정은 (기타 인자들 중)사용하는 응용 프로그램 코드, 이를 실행하는 하드웨어 그리고 클라이언트 작업 부하로 결정합니다. 최적 설정을 찾는 유일한 방법은 성능 테스트를 실시하는 것이며 다음 팁에서 설명합니다.
팁 27: 성능 테스트
앞서 언급했듯이, 성능은 하나의 기능입니다. 사이트의 성능을 향상시키려면, 성능 목표를 설정한 다음 목표에 도달할 때까지 조금씩 향상시키십시오. 프로젝트의 끝 부분을 위해 모든 성능 테스트를 아껴두지 마십시오. 종종, 프로젝트의 끝에서는 필요한 구조 변경을 하기에 너무 늦으며 따라서 고객을 실망시키게 됩니다. 성능 테스트를 일상 테스트의 부분으로 만드십시오. 성능 테스트는 ASP 페이지나 COM 개체와 같은 개별 구성 요소 또는 사이트 전체에 대해 수행할 수 있습니다.
많은 사람들이 하나의 브라우저를 사용하여 페이지를 요청함으로써 웹 사이트 성능을 테스트합니다. 이렇게 하면 사이트의 반응성에 대해 좋은 느낌을 받을 수 있지만 부하가 있는 상태에서 사이트의 성능을 평가하는 데 아무 도움이 못됩니다.
일반적으로 성능을 정확하게 측정하기 위해서는 전용 테스트 환경이 필요합니다. 이러한 환경에는 프로세서 속도, 프로세서 수, 메모리, 디스크, 네트워크 구성 등의 관점에서 프로덕션 하드웨어와 닮은 하드웨어가 있어야 합니다. 다음으로 동시 사용자의 수, 클라이언트의 요청 빈도, 그들이 열어보는 페이지의 형태 등 클라이언트의 작업 부하를 정의해야 합니다. 여러분의 사이트에서 실제적인 사용 데이터에 액세스가 없는 경우, 추정할 필요가 있습니다. 마지막으로, 예상한 클라이언트 작업 부하를 시뮬레이션할 수 있는 도구가 필요합니다. 이러한 도구를 구비하면 "N 명의 동시 사용자가 있는 경우 필요한 서버는 몇 대인가?"와 같은 질문에 답할 수 있습니다. 또한 병목현상을 무시하고 최적화를 위해 이를 공격 목표로 삼을 수 있습니다
 
 
28. 관련 리소스 링크를 읽어보십시오.

다음은 몇 가지 아주 유용한 성능 관련 리소스 링크들입니다. Developing Scalable Web Applications은 반드시 읽어보는 것이 좋습니다.

리소스

ASP 스크립트 최적화

IIS 조정

ADO 및 SQL Server

ASP 구성 요소 및 스레딩 모델 

딕셔너리 구성 요소

세션 상태

성능 및 확장성 

도구

문서

ASP 웹 사이트

ASP 스타일

XML

ASP 스크립트 최적화

Developing Scalable Web Applications

Got Any Cache? 저자: Nancy Winnick Cluts

Maximizing the Performance of Your Active Server Pages 저자: Nancy Winnick Cluts

15 Seconds: Performance Section

Enhancing Performance in ASP - Part I 저자: Wayne Plourde

When is Better Worse? Weighing the Technology Trade-Offs 저자: Nancy Winnick Cluts

Speed and Optimization Resources 저자: Charles Carroll

IIS 조정

The Art and Science of Web Server Tuning with Internet Information Services 5.0

Leveraging ASP in IIS 5.0 저자: J.D. Meier

Tuning IIS 4.0 for High Volume Sites 저자: Michael Stephenson

Tuning Internet Information Server Performance 저자: Mike Moore

Navigating the Maze of Settings for Web Server Performance Optimization 저자: Todd Wanke

Managing Internet Information Server 4.0 for Performance 저자: Hans Hugli

ADO 및 SQL Server

Top Ten Tips: Accessing SQL Through ADO and ASP 저자: J.D. Meier

Improve the Performance of your MDAC Application 저자: Suresh Kannan

Pooling in the Microsoft Data Access Components 저자: Leland Ahlbeck 및 Don Willits

SQL Server: Performance Benchmarks and Guides

Improving the Performance of Data Access Components with IIS 4.0 저자: Leland Ahlbeck

Microsoft Data Access Components (MDAC) and ActiveX Data Objects (ADO) Performance Tips 저자: Leland Ahlbeck

Microsoft SQL Server 7.0 Practical Performance Tuning and Optimization - The Server Perspective 저자: Damien Lindauer

Microsoft SQL Server 7.0 Practical Performance Tuning and Optimization - The Application Perspective 저자: Damien Lindauer

Accessing Recordsets over the Internet 저자: Dino Esposito

ASP 구성 요소 및 스레딩 모델

ASP Component Guidelines 저자: J.D. Meier

Q243548: INFO: Design Guidelines for VB Components under ASP

Threading Models Explained 저자: Nancy Winnick Cluts

So Happy Together? Using ActiveX components with Active Server Pages 저자: Nancy Winnick Cluts

Developing Active Server Components with ATL 저자: George Reilly

Agility in Server Components 저자: Neil Allain

Building High-Performance Middle-Tier Components with C++ 저자: Jon Flanders

Active Server Pages and COM Apartments 저자: Don Box

House of COM: Active Server Pages 저자: Don Box

House of COM: Contexts 저자: Don Box

House of COM: Performance Trade-offs of the Windows 2000 Component Execution Environment 저자: Don Box

Building COM Components That Take Full Advantage of Visual Basic and Scripting 저자: Ivo Salmre

Component Design Principles for MTS

딕셔너리 구성 요소

Creating a Page Cache Object 저자: Robert Coleridge

Abridging the Dictionary Object: The ASP Team Creates a Lookup-Table Object 저자: Robert Carter

Caprock Dictionary

Site Server Commerce Edition에는 딕셔너리 구성 요소가 들어 있습니다.

세션 상태

Q175167: HOWTO: Persisting Values Without Sessions

Q157906: HOWTO: How To Maintain State Across Pages with VBScript

XML-based Persistence Behaviors Fix Web Farm Headaches 저자: Aaron Skonnard

House of COM: Stateless Programming 저자: Don Box

성능 및 확장성

Blueprint for Building Web Sites Using the Microsoft Windows DNA Platform

Server Performance and Scalability Killers 저자: George Reilly

Microsoft Visual Studio Scalability Center

Fitch & Mather Stocks 2000

Tuning the FMStocks Application

High-Performance Visual Basic Apps 저자: Ken Spencer

Duwamish Books, Phase 4

Top Windows DNA Performance Mistakes and How to Prevent Them 저자: Gary Geiger 및 Jon Pulsipher

Building from Static HTML to High-Performance Web-Farms 저자: Shawn Bice

도구

Microsoft Web Application Stress Tool

I Can't Stress It Enough -- Load Test Your ASP Application 저자: J.D. Meier

Windows DNA Performance Kit

Monitoring Events in Distributed Applications Using Visual Studio Analyzer 저자: Mai-lan Tomsen

문서

Professional Active Server Pages 3.0, Wrox Press. (특히, Chapter 26:Optimizing ASP Performance, 저자: George Reilly 및 Matthew Gibbs 참조)

Microsoft Internet Information Services 5.0 Resource Guide(Windows 2000 Server Resource Kit와 함께 제공됨), Microsoft Press.

Microsoft Internet Information Server Resource Kit (for IIS 4.0), Microsoft Press.

Programming Distributed Applications with COM and Microsoft Visual Basic 6.0 저자: Ted Pattison, Microsoft Press.

Effective COM 저자: Don Box, Keith Brown, Tim Ewald, Chris Sells 및 Addison-Wesley.

Developing Web Usability: The Practice of Simplicity 저자: Jakob Nielsen, New Riders.

ASP 웹 사이트

Microsoft TechNet for IIS

LearnASP.com

4GuysFromRolla.com

15Seconds.com

AspToday.com

Asp101.com

AspLists.com. 여기에는 다음과 같은 특수 메일 목록이 들어 있습니다.

  • Fast Code!
  • ASP Advanced
  • Not NewbieState Management
  • Scalability
  • Visual Basic Components
  • XML
  • C++/ATL Component Building

UseIt.com: Web Usability

ASP 스타일

ASP Best Practices 저자: George Reilly

ASP Quick Lessons 저자: Charles Carroll

Planning for ASP 저자: John Meade

ASP Guidelines 저자: J.D. Meier

XML

Inside XML Performance 저자: Chris Lovett

Inside MSXML3 Performance 저자: Chris Lovett

'Computer > ASP' 카테고리의 다른 글

ASP 에서 UTF-8 처리  (0) 2011/11/29
성능 및 스타일 향상을 위한 25+ ASP 팁  (0) 2011/11/29
URLEncode  (0) 2011/11/29
ASP 서버 변수 출력  (0) 2011/11/29
Posted by 알찬돌삐

댓글을 달아 주세요

URLEncode

Computer/ASP 2011/11/29 10:03
URLEncode는 HTTP/URL에서 사용할 수 없는 공백, &, ?, %등의 기호를 URL을 통해 전송해야 할 경우, URL 대체 문자로 문자열을 변환하는 메소드[각주:1]이다.



URL 대체 문자는 아래와 같다.

공백             + 또는 %20
'                  %27
!                  %21
#                 %23
$                 %24
%                %25
&                %26
(                 %28
)                 %29
=                 %30
 
  1. 객체지향 프로그래밍(OOP)에서 메쏘드는 클래스의 일부분으로 정의되어, 그 클래스의 모든 객체에 포함되어야 하는 프로그램된 절차다. 클래스(즉 객체)는 하나 이상의 메쏘드를 가질 수 있다. 객체의 메쏘드는 그 객체에게 알려진 자료에만 접근이 가능하므로, 응용프로그램의 객체 집합체 내에서 데이터의 무결성을 확실하게 한다. 메쏘드는 여러 개의 객체들에서 재사용될 수 있다. 출처 http://k.daum.net/qna/openknowledge/view.html?qid=38Uts [본문으로]

'Computer > ASP' 카테고리의 다른 글

성능 및 스타일 향상을 위한 25+ ASP 팁  (0) 2011/11/29
URLEncode  (0) 2011/11/29
ASP 서버 변수 출력  (0) 2011/11/29
펌) 페이징 쿼리문 비교  (0) 2011/11/29
Posted by 알찬돌삐
TAG urlencode

댓글을 달아 주세요





ASP 에서 서버 변수를 출력하여 보려고 할때 사용하면 좋다.








  1. <%
  2. 'servervariables 컬렉션값 출력하기
  3. for each key in request.servervariables
  4.  response.write "<tr><td>"&key&"</td><td>"
  5.  
  6.  if request.servervariables(key) = "" then
  7.   response.write "&nbsp;" & vbcrlf        
  8.  else
  9.   response.write request.servervariables(key) & vbcrlf
  10.  end if
  11.  
  12.  response.write "</td></tr><tr>"
  13. next
  14. %>
 

'Computer > ASP' 카테고리의 다른 글

URLEncode  (0) 2011/11/29
ASP 서버 변수 출력  (0) 2011/11/29
펌) 페이징 쿼리문 비교  (0) 2011/11/29
펌) ASP 성능 향상 TIP.  (0) 2011/11/29
Posted by 알찬돌삐

댓글을 달아 주세요

출처 : http://www.knhead.pe.kr

 

 

 

제가 어느 페이징이 제일 빠를까.. 고민 하다가.. 테스트로 만들어 보았습니다.
총.. 6가지..입니다..

간단하게 쿼리를 설명해드리겠습니다.

1. SELECT TOP [불러올 총 게시물수] [출력 필드명] FROM [테이블 명]

  1번 리스트는 이 쿼리 구문을 써서 했고요. 현제 개시물까지 이동을 Rs.Move(이동할수) 로 처리 했습니다.

2. SELECT TOP [불러올 총 게시물수] [출력 필드명] FROM [테이블 명]    - 1번과 동일

  1번과 쿼리구문은 동이하고요. 레코드셋의 AbsolutePage를 이용해서 페이징을 했습니다.

3. SELECT TOP [불러올 총 게시물수] [출력 필드명] FROM [테이블 명]

   WHERE [글번호필드] NOT IN (SELECT TOP [제거할 게시물수] [글번호필드] FROM [테이블명])
   예전에 태요 사이트에서 보았던 쿼리 구문입니다.. NOT IN 때문에.. 문제시 되었던 쿼리구문이죠.

4. SELECT TOP [불러올 총 게시물수] [출력 필드명] FROM [테이블 명]
   WHERE [글번호] IN (SELECT TOP [페이지출력 갯수] [글번호] FROM
   (SELECT TOP [불러올 총 게시물수] [글번호] FROM [테이블 명]) AS A ORDER BY [글번호])
   ORDER BY [글번호] DESC

   이 쿼리 구문은 3번의 쿼리 구문의 문제점을 보완한 구문입니다. NOT IN 대신에 IN을 사용 했습니다.

5. SELECT TOP [페이지 출력갯수] [출력 필드명] FROM [테이블 명]
   WHERE [글번호] <= (SELECT MIN([글번호])
   FROM (SELECT TOP [제거할 게시물수] + 1 [글번호] FROM [테이블명]) AS A)

   5번째 쿼리 구문은 IN, NOT IN이 아닌 출력할 마지막 글번호 바로 앞이 글번호를 찾아서 처리를 해주는
   쿼리 구문입니다.

6. SELECT TOP [페이지 출력갯수] [출력 필드명] FROM [테이블명]
   WHERE [글번호] <= (SELECT MIN([글번호])
   FROM (SELECT TOP [제거할 게시물수] + 1 [글번호]
   FROM [테이블명] WHERE [인덱스] = [시작인덱스번호] AND [인덱스] = [끝인덱스번호]) AS A
   WHERE [인덱스] = [시작인덱스번호] AND [인덱스] = [끝인덱스번호])
   AND [인덱스] = [시작인덱스번호] AND [인덱스] = [끝인덱스번호]

   6번재 쿼리는.. 글에 인덱스(가칭)라는 필드를 하나 더 추가 해서.. 글 기본 2000개마다 (가변적입니다)
   인덱스를 증가 시켰습니다. 즉 2000개를 하나의 묶음으로 만든것입니다.
   그 인덱스를 기준으로 처리를 해주었습니다.(기본 개념은 영어 사전 입니다 ㅡㅡ;) 


위와 같이 간단한 기본 쿼리 구문을 설명? 했습니다.
게시물은 100만개를 넣고 테스트를 했습니다.
테스트 게시판을 보시려면.. 맨위에 각 게시판을 링크를 걸었습니다.
서버가 구려서.. 제대로 될지 모르지만..
제 노트북
(CPU : p4-1.8, RAM : 768Mb, 컴팩 프리자리오 2820AP, 환경 : 윈도우2003 MSSQL2000)
에서 테스트 해본 봐로는 처음페이지(1), 마지막 페이지(50000) 처리 시간이 아래와 같습니다.(단위 ms)

1 : 320    12289.06
2 : 273    11476.56
3 : 289    4406.25
4 : 289    2695.31
5 : 289    1218.75
6 : 7.81    23.44

엄청난 차이가 나죠??
기본적으로 글번호에 Clustered Index, 인덱스번호, 글깊이에 Non Clustered Index를 걸어 두었습니다.
엄청난 차이로 인해 테스트로 만든 저 또한 입이 쩍 벌어 집니다 ㅡㅡ;;

위 페이징 로직은 여기 저기서 줏어 듣고 ㅡㅡ; 확장 시킨 것입니다.

제가 내공 수위가 낮은 관계로 정확한 테스트를 행했는지 모르지만..
페이징으로 고생하시는 분들을 위해.. 간략하게 만들어 봤습니다.

기본 테스트는 제 홈페이지에서 해보시면 되구요.

테스트 asp파일은 [이곳] 에서 다운 받을수 있습니다.

제 홈에 있는 페이징 방법이 6번의 인덱스와 not in 으로 만들었습니다.
(그때는 걍.. 2000개 안쪽에서 처리 해주는 것이라 not in을 썻습니다 게시판이 필요 하시면..
  다운 받으셔서 저장 프로시저늬 리스트 부분을 수정 하시면. .더욱 쾨적하게 사용 하실수 있을것입니다)

p.s 서버가 구려서 노트북 보다는 성능이 낮게 나오네요. ㅡㅡ;
     궁금하신 점이나 문의 사항은 제 홈페이지의 테스트 게시판 버그 리포트에 적어 주시기 바랍니다.

'Computer > ASP' 카테고리의 다른 글

ASP 서버 변수 출력  (0) 2011/11/29
펌) 페이징 쿼리문 비교  (0) 2011/11/29
펌) ASP 성능 향상 TIP.  (0) 2011/11/29
펌) dext업로드 컴포넌트에 대해서..  (0) 2011/11/29
Posted by 알찬돌삐

댓글을 달아 주세요

[ASP성능 향상 팁]

1.   Option Explicit를 명시한다. 쓰지도 않는 변수들이 생기면 그만큼 메모리 낭비가 생기므로...

2.   배열사용 시 배열 재할당은 최대한 피한다.

3.   배열 사용이 빈번할 시 Dictionary 객체를 이용하여 가독성을 높인다.

4.   Stored Procedure를 사용한다. (일반 ASP자체 쿼리보다 최고 30% 성능 향상.)

5.   뷰테이블 사용 시 뷰테이블 자체에서 정렬을 해야 한다. 이미 만들어진 뷰테이블을 이용하여 Asp 코드에
서 정렬하면 속도가 크게 떨어진다. 최고 50%까지 느려지는 것을 목격했음.

6.   Query를 사용할 때 꼭 필요한 컬럼만 명시하여 불러오거나 이용해야 한다. SQL은 아주 정직해서 불러오
는 컬럼의 갯수(레코드 수가 동일하다고 가정시)에 비례하여 시간이 걸린다.

7. Recordset 객체 보다는 Command 객체를 이용하는 것이 빠르다. 10%정도의 향상을 볼 수 있었다.

8. Recordset 객체 사용시 CursorLocation를 적절한 것을 사용해야 한다. (1, 서버, 3. 클라이언트) 속도의 차
이가 클 수 있다. CursorType도 영향을 미친다. 반드시 테스트 필요. 보통은 CursorLocation은 클라이언트
에 두는 것이 추세다. 테스트때 클라이언트에 커서를 두었을때 서버에 두었을때보다 속도가 최고 3배이상 빨
라지는 것을 경험했다.

9.   1000글자가 넘어가는 문장의 경우는 변수에 담아서 한번에 Response.Write 하는 것보다는 한줄한줄 직
접 뿌려주는 것이 빠르다. <%= %>를 이용해 직접 뿌리는 것이 가장 빠르다. 괜히 변수에 잔뜩담아서 
Response.write 해보라 -_-;;; 아마 글자수의 제곱에 비례하여 느려질 것이다 -_-;;;

10.  사용한 객체는 반드시 Close, Nothing 해준다. 안해주면 메모리 누수가 일어난다. 웹서버들이 잘 죽는 경
우는 반드시 이것을 체크해야 한다.

11.  다중레코드를 이용할 시에는 Do until, Rs.MoveNext 구문보다는 GetRows() 함수를 이용하는 것이 빠르
다.(Stored Procedure와 함께 사용시 최고 40% 성능 향상, 단독으로 사용시 최고 20% 성능 향상.)

12.  사용자 Function을 만들어 쓰는 것이 디버깅 등에 좋다.

13. ADODB 객체 사용보다 OBJECT 객체를 사용하여 컨넥션, 레코드셋을 연다.

[잘못알려진 내용들]

1.  Inlcude를 많이 시키면 속도가 느려진다고 일반적으로 알려져 있지만 실제로는 속도차이가 전혀 없다.

2. 긴문장이나 Html과 Asp 태그를 혼합해서 많이 쓰면 느려진다고 알려져 있으나 실제로는 차이가 없거나 혼
합해서 쓰는 것이 오히려 빨랐다. 오히려 긴 Html 태그를 asp 변수에 담아 Response한 결과 1000글자가 넘어
갈 수록 단순히 혼합해서 쓴 소스의 수행시간의 제곱에 비례하게 느려지는 것이 발견되었다.

3. 뷰테이블에 아무리 많은 테이블, 컬럼들을 Join 해도 단일 테이들의 같은 수의 컬럼을 사용하는 속도와 동
일하다.

'Computer > ASP' 카테고리의 다른 글

펌) 페이징 쿼리문 비교  (0) 2011/11/29
펌) ASP 성능 향상 TIP.  (0) 2011/11/29
펌) dext업로드 컴포넌트에 대해서..  (0) 2011/11/29
펌) asp에서 디비작업 최적화하기  (0) 2011/11/29
Posted by 알찬돌삐

댓글을 달아 주세요

DEXT Upload 사용법
 
1 덱스트 업로드 컴포넌트를 사용하기위한 몇가지 유의 사항
2 간단한 업로드
3 다중파일 업로드
4 업로드 파일 용량 제한
5 업로드 파일을 유일한 파일이름으로 저장
6 업로드된 파일로부터 정보 얻기
7 파일 다운로드
8 DEXT vs SiteGalaxy
9 한글이 깨지는 문제
 
 
1. 덱스트 업로드 컴포넌트를 사용하기위한 몇가지 유의 사항
 - www폴더밑의 자료실 디렉토리에는 보안상 쓰기/수정권한을 주지 않습니다. 
   따라서 파일을 업로드 할 때에는 www하위에 임의폴더( 예) upload )를 지정하신 후
          당사 고객지원사이트에서 (http://www.Mydirect.co.kr)에서 쓰기/수정권한을 요청해주셔야합니다.
 - 덱스트 업로드 컴포넌트 메뉴얼에는 가상경로로 업로드라는 부분이 있습니다. 
          다이렉트에서는 절대경로를 알려드리므로 가능하시면 가상경로보다 절대경로를 이용해 주시기 바랍니다.
          보다 빠르게 서비스될 수 있기 때문입니다.
 - 고객님들이 자주 문의하시는 내용은 submit을 하면 값이 넘어오지 않는다는것입니다.
   그것은 DefaultPath를 설정하기 전에 값을 받는다던지 아니면 DefaultPath를 잘못 설정 했기 때문입니다.
   덱스트 업로드 컴포넌트는 파일을 저장하기전에 임시파일을 만듭니다. 
   그 임시파일은 DefaultPath에 저장이 되는것이기 때문에 값을 받기 전에 항상 DefaultPath를 설정 하셔야 합니다.
 
 - 이 후에 나오는 예제들은 모두 다이렉트 실정에 맞도록 경로를 설정한 예제들 입니다.   
        - www\upload 폴더는 고객님이 임의 생성 후 저희측에 쓰기/수정 권한을 요청하셔야 합니다.
        - www.direct.co.kr -> 고객지원 -> AS접수 ->쓰기 권한 요청
        - 절대경로는 www.direct.co.kr -> 고객지원 -> 첫메뉴의 MyService의 고객정보란에서 확인이 가능합니다.
   www의 절대 경로 - D:\w000000\www
   upload(임의생성폴더)의 절대 경로 - D:\w000000\www\upload

2. 간단한 업로드
 사용폴더 
  - ASP파일이 위치 할 폴더 :     D:\w000000\www\Simple_upload
  - 업로드된 파일이 저장될 폴더(임의생성폴더) : D:\w000000\www\upload\Simple_upload
 예제 소스
  [Write.htm]
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
   <Form Name="form1" Method="post"  Action="write_ok.asp"  Enctype="multipart/form-data">
    
    <Input Type="File" Name="File1">
    <Input Type="Submit" Value="업로드">
     
   </Form>
   </BODY>
   </HTML>
  
  [Write_ok.asp]
   
   <%
    Response.Expires = 0
    Response.Buffer = True
    ON ERROR RESUME NEXT
    'DEXT.FileUpload 개체 생성
    Set uploadform = Server.CreateObject("DEXT.FileUpload")
    uploadform.DefaultPath = "D:\w000000\www\upload\Simple_upload"

    '또한 파일이 저장될 경로에는 쓰기 권한이 필요합니다. 
    FileName = uploadform("File1").Save 라고 해도 상관 없슴.
    If Err then
        Response.Write Err.number & "<br>" & Err.source & "<br>" & Err.description
        Set uploadform = Nothing
        Response.End
    End if
    Set uploadform = Nothing
   %>
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
    <TABLE>
        <TR>
      <td colspan="2" align="center"><b>Upload successfully!!</b></TD>
        </TR>
        <TR>
      <TD width="200">Original Path</td>
      <TD width="300"><%=uploadform.FilePath%></TD>
        </TR>
        <TR>
      <TD width="200">Upload Path</TD>
      <TD width="300"><%=FileName%></TD>
        </TR>
        <TR>
      <TD width="200">File Size</TD>
      <TD width="300"><%=uploadform.FileLen%></TD>
        </TR>
        <TR>
      <TD width="200">Mime Type</TD>
      <TD width="300"><%=uploadform.MimeType%></TD>
        </TR>
    </TABLE>
   </BODY>
   </HTML>
 
3. 다중파일 업로드
 사용폴더 
  - ASP파일이 위치 할 폴더 :     D:\w000000\www\Multiple_upload
  - 업로드된 파일이 저장될 폴더(임의생성폴더) : D:\w000000\www\upload\Multiple_upload
 예제 소스
  [Write.htm]
   
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
   <Form Name="form1" Method="post"  Action="write_ok.asp"  Enctype="multipart/form-data">
    
    TYPE 1.<br>
    <Input Type="File" Name="File1"><br>
    <Input Type="File" Name="File2"><br>
    <Input Type="File" Name="File3"><br>
    <p>&nbsp;</p>
    TYPE 2.<br>
    <Input Type="File" Name="File"><br>
    <Input Type="File" Name="File"><br>
    <Input Type="File" Name="File"><br>
    <br>
    <Input Type="Submit" Value="업로드">
     
   </Form>
   </BODY>
   </HTML>
  
  [Write_ok.asp]
   <%
    Response.Expires = 0
    Response.Buffer = True
    'ON ERROR RESUME NEXT
    'DEXT.FileUpload 개체 생성
    Set uploadform = Server.CreateObject("DEXT.FileUpload")
    uploadform.DefaultPath = "D:\w000000\www\upload\Multiple_upload"

    '또한 파일이 저장될 경로에는 쓰기 권한이 필요합니다. 
    'TYPE 1
    uploadform("File1").Save 
    uploadform("File2").Save 
    uploadform("File3").Save
    'TYPE 2
    For i = 1 to uploadform("Files").Count
    
       uploadform("Files")(i).Save
 
    Next

    If Err then
        Response.Write Err.number & "<br>" & Err.source & "<br>" & Err.description
        Set uploadform = Nothing
        Response.End
    End if
    Set uploadform = Nothing
   %>
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
    <TABLE>
        <TR>
      <td colspan="2" align="center"><b>Upload successfully!!</b></TD>
        </TR>
    </TABLE>
   </BODY>
   </HTML>
 
4. 업로드 파일 용량 제한
 MaxFileLen property를 이용하면 업로드 가능한 최대 파일 크기를 제한할 수 있다. 만일 지정된 크기보다 
 큰 파일 을 업로드 할 경우에는 다음과 같은 오류가 발생하게 된다.
  
  DEXTUpload error '80040200'
  Warning: File size must be less than 5242880 Bytes.
  /form_process.asp, line 27
 다음 예제와 같이 FileLen property를 이용해서 최대 파일 크기를 초과하지 않는 경우에만 Save Method를 
 호출하게 하는 방법으로 오류발생 없이 업로드 파일크기 제한에 대한 처리를 커스터마이징 할 수도 있다.

 사용폴더 
  - ASP파일이 위치 할 폴더 :     D:\w000000\www\LimitSize
  - 업로드된 파일이 저장될 폴더(임의생성폴더) : D:\w000000\www\upload\LimitSize
 예제 소스
  [Write.htm]
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
   <Form Name="form1" Method="post"  Action="write_ok.asp"  Enctype="multipart/form-data">
    
    <Input Type="File" Name="File1">
    <Input Type="Submit" Value="업로드">
     
   </Form>
   </BODY>
   </HTML>
  
  [Write_ok.asp]
   <%
    Response.Expires = 0
    Response.Buffer = True
    'ON ERROR RESUME NEXT
    'DEXT.FileUpload 개체 생성
    Set uploadform = Server.CreateObject("DEXT.FileUpload")
    uploadform.DefaultPath = "D:\w000000\www\upload\LimitSize" 
    uploadform.MaxFileLen = 1024768
    If uploadform("file1").FileLen > uploadform.MaxFileLen Then
       Response.Write "File size must be less than 1MBytes.<br>"
       Response.Write "Press the back button on your browser...<br>"
    Else
       uploadform("File1").Save
       Response.Write "Upload successfully!!"

    End If
    Set uploadform = Nothing

   %>
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
   </BODY>
   </HTML>

5. 업로드 파일을 유일한 파일이름으로 저장
 Save, SaveVirtual, SaveAs, SaveAsVirtual Method는 기본적으로 업로드된 파일을 서버에 저장할 때 
 해당 경로에 동일한 이름의 파일이 존재할 경우 겹쳐쓰게 된다. 겹쳐쓰지 않고 유일한 파일명을 
 구해서 저장하고 싶으면 두 번 째 인자인 bOverwrite를 명시적으로 False로 지정하면 된다.
 사용폴더 
  - ASP파일이 위치 할 폴더 :     D:\w000000\www\SaveAsUnique
  - 업로드된 파일이 저장될 폴더(임의생성폴더) : D:\w000000\SaveAsUnique
 예제 소스
  [Write.htm]
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
   <Form Name="form1" Method="post"  Action="write_ok.asp"  Enctype="multipart/form-data">
    
    <Input Type="File" Name="File1">
    <Input Type="Submit" Value="업로드">
     
   </Form>
   </BODY>
   </HTML>

  [Write_ok.asp]
   
   <%
    Response.Expires = 0
    Response.Buffer = True
    'ON ERROR RESUME NEXT
    'DEXT.FileUpload 개체 생성
    Set uploadform = Server.CreateObject("DEXT.FileUpload")
    uploadform.DefaultPath = "D:\w000000\www\upload\SaveAsUnique"

    '또한 파일이 저장될 경로에는 쓰기 권한이 필요합니다. 
    FileName = uploadform("File1").Save( ,false)              '<==============
    If Err then
        Response.Write Err.number & "<br>" & Err.source & "<br>" & Err.description
        Set uploadform = Nothing
        Response.End
    End if
   %>
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
    <TABLE>
        <TR>
      <td colspan="2" align="center"><b>Upload successfully!!</b></TD>
        </TR>
        <TR>
      <TD width="200">Original Path</td>
      <TD width="300"><%=uploadform.FilePath%></TD>
        </TR>
        <TR>
      <TD width="200">Upload Path</TD>
      <TD width="300"><%=FileName%></TD>
        </TR>
        <TR>
      <TD width="200">File Size</TD>
      <TD width="300"><%=uploadform.FileLen%></TD>
        </TR>
        <TR>
      <TD width="200">Mime Type</TD>
      <TD width="300"><%=uploadform.MimeType%></TD>
        </TR>
    </TABLE>
   </BODY>
   </HTML>
 위 예제에서 D:\w000000\www\upload\SaveAsUnique 폴더에 sample.zip이라는 파일이 이미 존재할 경우 
 업로드된 파일은 "D:\w000000\www\upload\SaveAsUnique\sample(2).zip" 이라는 이름으로 저장되어 
 다음과 같은 결과 페이지를 보여주게 된다.
 [ 실행결과 ]
 uploaded file : "D:\w000000\www\upload\SaveAsUnique\sample(2).zip"
 
6. 업로드된 파일로부터 정보 얻기
 업로드된 파일에 대한 정보를 얻을 수 있도록 다음과 같은 Property들이 제공된다.
 .FileLen : 업로드된 파일의 길이
 .FileName : 업로드된 파일의 이름(경로제외)
 .FilePath : 업로드된 파일의 전체경로
 .MimeType : 업로드된 파일의 Mime Type
 ※ .FileName과 .FilePath는 사용자가 업로드한 오리지널 파일에 대한 이름과 전체경로값을 가진다.
 업로드되어 서버에 저장된 파일의 전체경로값은 .Save, .SaveAs Method 등의 리턴값으로부터 얻을 수 있다.

 사용폴더 
  - ASP파일이 위치 할 폴더 :     D:\w000000\www\FileInfo
  - 업로드된 파일이 저장될 폴더(임의생성폴더) : D:\w000000\www\upload\FileInfo
 예제 소스
  [Write.htm]
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
   <Form Name="form1" Method="post"  Action="write_ok.asp"  Enctype="multipart/form-data">
    
    <Input Type="File" Name="File1">
    <Input Type="Submit" Value="업로드">
     
   </Form>
   </BODY>
   </HTML>

  [Write_ok.asp]
   <%
    Response.Expires = 0
    Response.Buffer = True
    ON ERROR RESUME NEXT
    'DEXT.FileUpload 개체 생성
    Set uploadform = Server.CreateObject("DEXT.FileUpload")
    uploadform.DefaultPath = "D:\w000000\www\upload\FileInfo"

    '또한 파일이 저장될 경로에는 쓰기 권한이 필요합니다. 
    FileName = uploadform("File1").Save
    Response.Write "[Uploaded File Information] <BR>"
    Response.Write "FileName : " & uploadform("File1").FileName & "<BR>"
    Response.Write "FullPath : " & uploadform("File1").FilePath & "<BR>"
    Response.Write "FileLength : " & uploadform("File1").FileLen & " Byte(s)<BR>"
    Response.Write "MimeType : " & uploadform("File1").MimeType & "<BR>"
 
    If Err then
        Response.Write Err.number & "<br>" & Err.source & "<br>" & Err.description
        Set uploadform = Nothing
        Response.End
    End if
   %>
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
   </BODY>
   </HTML>
 
7. 파일 다운로드
 ※ 여기서 ,"inline"이란 속성을 "attachment"라는 속성으로 바꾸어 주면 액셀파일이나 그림파일 같은
 브라우저 인식 파일에 대해서도 "파일 다운로드" 대화상자가 항상 나타나도록 할 수 있습니다.
 하지만, 현재 "attachment"속성이 제대로 작동하는 웹브라우저는 넷스케이프 네비게이터의 모든 버전과,
 인터넷 익스플로러 5.0뿐입니다. 인터넷 익스플로러 4.01과 5.5버전에서는 "attachment"를 제대로 인식하지 
 못하는 웹브라우저 버그가 있습니다.
 거기다, 인터넷 익스플로러 5.5 sp1의 경우는 "attachment"를 썼을 때 엉뚱하게도 download.asp를 링크하고
 있는 asp파일(또는 HTML파일)의 실행결과 HTML을 다운로드 받아버리는 버그가 있습니다.
 결론적으로, "파일 다운로드" 대화상자가 항상 뜨도록 하려면 "attachment" 속성을 써야 하는데, 현재 이 속성에 
 대한 인터넷 익스플로러 버그 문제가 있기 때문에 "attachment"는 쓰지 않는 것이 좋고, 어쩔수 없이 "inline"을 
 써야 합니다만, 이것을 쓰게 되면 웹브라우저 인식파일은 브라우저 상에 바로 오픈되어 나타나게 됩니다.

 사용폴더 
  - ASP파일이 위치 할 폴더 :     D:\w000000\www\Download
  - 다운로드 받을 파일이 위치한 폴더(임의생성폴더) : D:\w000000\www\upload\Download
 예제 소스
  
  [Download.asp]
   
   <%
    Response.Buffer = False
    filepath = "D:\w000000\www\upload\Download\DEXTUpload Manual.zip"
    filename = "DEXTUpload Manual.zip"
    Response.AddHeader "Content-Disposition","inline;filename=" & filename
    Set objFS = Server.CreateObject("Scripting.FileSystemObject")
    Set objF = objFS.GetFile(filepath)
    Response.AddHeader "Content-Length", objF.Size
    Set objF = nothing
    Set objFS = nothing
    Response.ContentType = "application/x-msdownload"
    Response.CacheControl = "public"
    Set objDownload = Server.CreateObject("DEXT.FileDownload")
    objDownload.Download filepath
    Set uploadform = Nothing
   %>
 
8. DEXT vs SiteGalaxy
 다음은 덱스트 업로드를 이용한 파일 업로드와 사이트 겔럭시를 이용한 파일업로드 입니다.
 아래 소스에서 주석 처리부분만 바꿔주시면 됩니다.
 
 사용폴더 
  - ASP파일이 위치 할 폴더 :     D:\w000000\www\dext   --> Dext라는 디렉토리를 만든다.
                                               D:\w000000\www\SiteGalaxy --> SiteGalaxy라는 디렉토리를 만든다.
  - 다운로드 받을 파일이 위치한 폴더 : D:\w000000\www\upload\DEXT
       D:\w000000\www\upload\SiteGalaxy
 예제 소스
  [Write.htm]
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
   <Form Name="form1" Method="post"  Action="write_ok.asp"  Enctype="multipart/form-data">
    
    <Input Type="File" Name="File1">
    <Input Type="Submit" Value="업로드">
     
   </Form>
   </BODY>
   </HTML>

  [Write_ok.asp]
   <%
    Response.Expires = 0
    Response.Buffer = True
    ON ERROR RESUME NEXT

'====================== DEXT 업로드를 이용한 업로드 ================================== 
    'DEXT.FileUpload 개체 생성
    Set uploadform = Server.CreateObject("DEXT.FileUpload")
    uploadform.DefaultPath = "D:\w000000\www\upload\DEXT" 
    uploadform("File1").Save
    '
'=====================================================================================

'====================== SiteGalaxy를 이용한 업로드  ==================================
    'SiteGalaxyUpload 개체 생성
    'Set uploadform = Server.CreateObject("SiteGalaxyUpload.Form")
    'DefaultPath = "D:\w000000\www\upload\SiteGalaxy"
    'tmp_filename = uploadform("File1").FilePath
    'FileName = Mid(tmp_filename, InstrRev(tmp_filename, "\") + 1)
    'uploadform("File1").SaveAs DefaultPath & "\" & FileName
'=====================================================================================        
    
    If Err then
        Response.Write Err.number & "<br>" & Err.source & "<br>" & Err.description
        Set uploadform = Nothing
        Response.End
    End if
    Set uploadform = Nothing
   %>
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <HTML>
   <HEAD>
   <TITLE> New Document </TITLE>
   <META http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
   </HEAD>
   <BODY>
    <TABLE>
        <TR>
       <td colspan="2" align="center"><b>Upload successfully!!</b></TD>
        </TR>
   </BODY>
   </HTML>
   
 
9. 한글이 깨지는 문제
 현재 웹브라우저에서 지원하는 한국어 코드 페이지로는 한국어(EUC)/한국어(ISO)/한국어 
 이렇게 세가지가 있습니다. 그런데 일반적으로 사용하는 한국어(EUC)나 한국어(ISO)는 
 지원하는 한글의 수가 그냥 한국어(이것은 사실 KS_C_5601-1987 입니다)보다 적다는 사실입니다. 
  
 예를 들어 지금 문제가 되고 있는 "쫒"이라는 글자나 "얖"이라는 글자를 한국어(EUC)로 인코딩하면, 
 "쫒"이라는 글자는 &#51922;로 "얖"이라는 글자는 &#50582;로 나오게 됩니다. 
 이는 DEXTUpload를 사용하지 않고 ASP의 Request로 그냥 읽어도 마찬가지입니다. 
 (HTML로 보여지는 웹브라우저 화면에는 글자가 제대로 나오지만 실제 소스보기를 
 해보면 위와 같은 값이 나옵니다.)
  
 즉, 한국어(EUC)나 한국어(ISO) 코드 페이지를 사용하면 자주 쓰이지 않는 일부 한글문자들이 
 웹에서 정상적으로 처리되지 않고 위와 같이 문자코드값으로 나오는데, 이는 이들 코드체계가 
 외국에서 만들어진 완성형문자체계이다보니 아무래도 지원하는 글자수가 적은 듯 합니다.
  
 반면에 우리나라에서 만들어진 한글코드체계인 한국어(KS_C_5601-1987 )는 거의 대부분의 
 한글이 웹에서도 제대로 처리가 되는것을 확인할 수 있었습니다.
  
 결론적으로, 업로드 폼작성 ASP페이지에
 <meta http-equiv="Content-Type" content="text/html; charset=euc-kr"> 대신
 <meta http-equiv="Content-Type" content="text/html; charset=ks_c_5601-1987">
 를 사용해 보면(업로드 처리 페이지는 어떤 코드체계를 갖건 상관없습니다.) 글자가
 깨지지 않고 정상적으로 처리되는 것을 보실 수 있을 것입니다.


출처 http://blog.naver.com/dadaul/40004157401

'Computer > ASP' 카테고리의 다른 글

펌) ASP 성능 향상 TIP.  (0) 2011/11/29
펌) dext업로드 컴포넌트에 대해서..  (0) 2011/11/29
펌) asp에서 디비작업 최적화하기  (0) 2011/11/29
ASP CDONTS 메일 발송  (0) 2011/11/29
Posted by 알찬돌삐

댓글을 달아 주세요

흔히 ASP의 VBscript성능은 PHP비해 나쁘지 않지만, PHP+Mysql은 특별하게 빨라서 전체적인 웹포퍼먼스는 
그쪽이 좋다고들 말합니다(물론 Mysql감당할만한 사이트인 경우겠지만)
ASP에서는 역시 DB작업과 관련되어 최적화에 최적화를 하는 수밖엔 없는거죠.
제가 그간 사이트제작과, 서버관리를 하면서 느낀 DB의 최적화 10가지 방법을 간단히 적어보겠습니다.
(설명이 길어 이후 존칭을 생략합니다)
------------------------------------------------------------------------------
1. cachesize를 지정한다.
ASP의 주요임무는 DB에서 쿼리셋을 가져와서 렌더링 하는 것이다. 
그 구조를 자세히 생각해보자(커서가 DB측에 있는 일반적인 경우)
   SQLserver(또는 기타DB) → IIS의 asp프로세스 → ADO.recordset 쿼리셋을 DB와 synk 
   → movenext때마다 DB서버와 연동 → 매결과를 asp프로세스 메모리에 적재 
   → 최종결과를 HTML로 렌더링해서 IIS에 전달 → 클라이언트에게 flush
대략 이렇다. 단절된 레코드셋을 사용하거나 getRows로 배열로 환원하지 않는다면
'movenext때마다 DB서버와 연동'
이란 엄청난 일이 매 페이지마다 일어난다(커넥션은 풀링하지만)
그렇다고 맨날 배열로 참조하기도 싫고 단절된 레코드셋을 만들기도 싫다면 어떻게 해야할까?
'ADO.recordset 쿼리셋을 DB와 synk' 이 부분을 'ADO.recordset 쿼리셋 전체를 웹서버메모리에 적재'
이렇게 해주면 'movenext때마다 DB서버와 연동' 이란 작업은 'movenext때마다 메모리참조'로 바뀌게 되어 비
약적인 성능향상이 이루어진다. 하지만 얻는게 있으면 잃는게 있는법이다. 속도는 향상되나 그만큼의 캐쉬메
모리가 IIS서버에게 필요하다. 
따라서 아무 쿼리셋이나 전부 메모리에 적재하는 것은 어리석다. 그렇다고 특정 byte만큼 적재하다간 레코드
의 일부만 적재되고 짤리는 일이 있어서 말이 안된다.
가장 현명한 캐쉬방법은 '적당한 레코드를 캐쉬에 적재한다' 로 생각해볼 수 있다.
즉 100개의 레코드를 부른다면 앞에 30개정도는 캐쉬에서 처리하고 뒤에 70개만 디비와 synk하는 방법도 있다
ADO.recordset은 이러한 유연한 사고를 지원한다.
      recordset.casheSize=캐쉬할 레코드수
이러한 형식으로 사용할 수 있으며 기본값은 1이다.
즉 'select count(*) from board'와 같은 레코드가 1개만 반환되는 경우는 이미 캐쉬에 잡힌다는 뜻이다.
하지만 게시판에 흔히 쓰이는 'select top 10 * from board'와 같은 쿼리는 캐쉬를 따로 잡아줘야한다.
cacheSize를 사용할때 주의할 점은 반드시 레코드셋을 오픈하기 전에 설정해야만 의미가 있다는 것이다(당
연하게도!)
   strSQL="select top 30 * from board"
   rs.cacheSize=30
   rs.open strSQL,conn,0,1,1
이런 식으로 사용되어야한다. 쿼리결과가 정확하게 몇개의 레코드를 반환할지 모를 경우에도 유용하다.
대충 생각하기에 100개 안쪽이라면
   rs.cacheSize=100
이렇게 설정하면 100개만큼 메모리를 낭비하는가? 답은 아니다이다. 
생성된 레코드수만큼만 캐쉬하는 것이다. 
마지막으로 cacheSize를 사용할때 가장 유의할 점은 캐쉬될 용량이다.
레코드의 수라곤해도 그 레코드하나의 용량에 따라 캐쉬에 할당될 메모리의 양은 천차만별이다.
   select userid,count(*) from board group by userid
이런 쿼리는 사실 cacheSize=500을 해도 그닥 두려울게 없다. 캐쉬될 용량은 다음과 같이 계산해볼 수 있다.
   1record   용량 userid(12byte)+count(4byte)=16byte
   캐쉬전체 용량 16byte * 500 = 8000byte = 8kbyte
잘해봐야 8k가 두렵지는 않다. 하지만 아래 쿼리를 보자.
   select rowid,subject,contents,regdate,userid,hit from board
이것은 게시판을 읽어드릴때 일반적인 쿼리다. 100개만 캐쉬한다면 용량이 어떻게 될까.
   1record   용량 rowid(4)+subject(100)+contents(평균1000)+regdate(4)+userid(12byte)+hit(2) = 1122byte
   캐쉬전체 용량 1122byte * 100 = 112,200byte ≒ 112kbyte
이렇게 되면 얘기가 다르다. 10명의 동시접속자만 붙어도 1메가씩 떨어져나간다. 무서운 것이다.
따라서 캐쉬사이즈는 항상 그 용량을 고려해서 설정하는 습관을 들이도록 하자.
------------------------------------------------------------------------------
2. ADO페이징을 사용하지 않는다.
이 부분은 길게 설명하자면 한없이 길어지지만 간단히 설명하자면 
.PageSize, .AbsolutePage, .PageCount 시리즈를 사용하지 말라는 것이다.
그럼 어떻게? Mysql처럼 limit를 응용해서 두개의 top를 이용하는 것이다.
원리는 아래와 같다.
  1. 전체 레코드 수를 얻어온다. ex) RowCount=rs(0) - select count(*) from board
  2. 다음의 변수를 셋팅한다.
     PageSize - 한페이지 몇개의 로우가 보일지(직접할당 'PageSize=13')
     AbsolutePage - 현재 페이지(직접할당 'AbsolutePage=13')
     PageCount - 전체 페이지수(계산식 'PageCount = CInt((RowCount-1)/PageSize)+1' )
  3. 위의 변수를 이용해 쿼리를 구성한다.
     쿼리예) board테이블의 keyField가 rowid인 경우
     "select top " & PageSize & " * from board " &_
     "where rowid not in ( select top " & ((AbsolutePage-1)*PageSize) & " rowid from board)"
왜 이용하지 말라고 하는가하면 레코드셋의 페이징은 전체 레코드에 대해서 처리하기 때문에 용량이 큰 테이
블에서는 너무 큰 부하를 주기 때문에 인덱스를 이쁘게 잡은 테이블에서 위의 조건으로 indexSeek을 하는 것
과는 너무나 성능차이가 나기 때문이다.
------------------------------------------------------------------------------
3. ado객체의 옵션까지 상세히 설정한다.
레코드셋이나 커넥션객체를 다룰때 뒤에 인자를 세밀하게 조정하라는 얘기는 대부분의 책에 씌여져있으니 
자세히 다루지는 않겠다.
샘플로 쿼리로부터 레코드셋을 오픈하는 경우와 쿼리로 커넥션객체를 작업하는 샘플만 보자.
rs.open strSQL,conn,0,1,1
conn.execute strSQL,,1+&H80
(필자는 먼가 그 상수값을 외우는게 오히려 귀찮아서 걍 원래 변수값을 외워서 쓰고 있다..=.=;)
레코드셋 샘플은 전진전용커서,읽기전용락,커맨드는 일반 텍스트 라는 뜻의 옵션이다(순서대로)
execute 샘플은 커맨드는 일반 텍스트이고 + 레코드는 반환하지 말아라 라는 뜻의 옵션이다.
------------------------------------------------------------------------------
4. IsClientConnected를 사용한다.
Response.IsClientConnected 이란 메써드를 이용하면 asp를 호출한 클라이언트가 여전히 그 창을 닫지 않고 
서버의 응답을 기다리고 있는지 확인할 수 있다.
근데 대체 이걸 왜 사용할까? 간단히 예를 들면 복잡한 DB작업이나, 결제모듈등의 작업을 하는 경우 작업의 
요청자가 지루함을 이기지 못하고 페이지를 닫아버릴 때가 있다.
이런 경우 여러가지 문제가 야기되기 때문에 긴시간을 처리하는 asp는 마지막에 위 메써드를 이용해서 여전
히 클라이언트가 대기중인지 아닌지를 판별하여 대기중이라면 처리를 완료하고 아니면 롤백시키는 식으로 
구조를 짤 수 있다.(정말 시간이 긴 처리라면 중간중간에도 삽입해서 계속 확인해갈 수도 있고^^)
------------------------------------------------------------------------------
5. getRows와 getString을 활용한다.
특별하게 레코드셋으로 필터링하거나 검색할것이 아니라 단순히 루프를 돌릴것이라면 구지 무거운 레코드셋
으로 할 필요도 없고 자원도 빨리 반환할수록 좋다.
일반적으로 getRows를 사용하기 전의 루프문을 보면 다음과 같다.
rs.open strSQL,0,1,1
if not rs.EOF then
 do until rs.EOF
  response.write rs(0)&"-"&rs(1)
  rs.movenext
 loop
end if
rs.close
set rs=nothing
이것을 getRows로 바꾸면 아래와 같다.
rs.open strSQL,0,1,1
if not rs.EOF then arrTemp=rs.getrows
rs.close
set rs=nothing
if isArray(arrTemp) then
  for i=0 to Ubound(arrTemp,2)
    response.write arrTemp(0,i)&"-"&arrTemp(1,i)
  next
end if
레코드셋을 반환하는 시점도 훨씬 앞이고 게다가 일괄적으로 하나의 ASP블럭에서 여러가지 테이블 쿼리를 
처리하고 디자인 렌더링 부분에서는 배열루프로 처리할 수도 있다.
(물론 훨씬 빠르다)
getString도 많이 사용하는데 주로 단일 필드를 검색한 결과를 문자열로 만들때 편한다.
일반적인 사용방법은 아래와 같다.
SQLstring=rs.getString(2,,",","<BR>","null")
구문이 좀 복잡해보이는가? 2는 adClipString라는 상수대신에 사용한 값인데 거의 대부분의 경우에 저 값이 들
어가야하고, 그 다음 비워둔곳은 레코드 몇개만 치환할까인데 비워두면 다 받아준다. 
그 다음은 필드와 레코드의 구분자를 무엇으로할까이고 마지막은 널인 값은 무엇으로 치환하나에 대한 옵션
이다.
------------------------------------------------------------------------------
6. 연결문자열을 최적화한다.
이 글은 아래에도 있는 내용이라 생략하겠다.(MS SQL연결문자열에 Net-Library와 디비서버지정 참조)
------------------------------------------------------------------------------
7. 통계테이블 활용
디비를 설계할때는 항상 비용개념을 생각해봐야한다. 즉 insert나 update가 많은가 아니면 select가 많을 것인
가에 대한 숙제다.
일반적으로 게시판은 select가 압도적으로 많기 때문에 insert시에 비용을 더 책정해주면 select가 아름다워진
다. 즉 count(*), top, max 등을 사용할 부분을 간단히 트리거를 걸어두어 통계만 수집하는 테이블을 따로 작성
해두면 select시에는 단순하게 indexSeek으로 조회할 수 있기 때문에 훨씬 비용이 절감된다.
너무 뜬구름잡는 얘기같으니 트리거의 샘플을 하나보자.
CREATE TRIGGER insertBoard ON [dbo].[board] 
After INSERT,UPDATE
AS
declare @boardid int, @boardrowid int,@boardCNT int,@regdate datetime,@subject varchar(100),@cnt tinyint
   select @boardid=boardid from inserted
   select top 1 @boardrowid=rowid,@regdate=regdate,@subject=subject from board where boardid=@boardid 
and active=1
   select @boardCNT=count(*) from board where boardid=@boardid and active=1
   select @cnt=count(*) from boardstat where boardid=@boardid
   if @cnt>0
      update boardStat set boardrowid=@boardrowid,regdate=@regdate,subject=@subject,boardCNT=@boardCNT 
where boardid=@boardid
   else
      insert into boardStat(boardid,boardrowid,subject,regdate,boardCNT)values
(@boardid,@boardrowid,@subject,@regdate,@boardCNT)
위의 샘플은 BOARDID란 값으로 하나의 BOARD테이블에서 여러개의 게시판을 처리해주는 테이블을 가정하
고 짠 트리거인데, 간단히 설명하자면 insert가 되면 inserted에서 값을 확인해서 boardStat란 테이블에 해당레
코드가 있으면 최신값으로 업데이트를 아니면 insert를 하라는 것이다.
위의 트리거가 있으면
select count(*) from board where boardid=19 and active=1
이런 쿼리는
select cnt from boardStat where boardid=19
이렇게 바뀌게 된다.
boardid에 인덱스가 이쁘게 잡혀있다면 성능차이는 설명할 필요가 없을것이다.
------------------------------------------------------------------------------
8. 단절된 레코드셋을 사용한다.
웹서버가 여러대인 경우 단절된 레코드 셋을 사용하면 디비서버의 부하를 웹서버가 가져가기 때문에 상당한 
성능향상이 일어난다. (하지만 앞서 말했던 getRows보다는 아니다) 간단히 소스의 변화만 보겠다.
call DB_Open()
call RS_Open()
rs.open sql,conn,0,1,1
위의 일반적인 소스를 아래와 같이 바꾼다.
call DB_Open()
call RS_Open()
rs.CursorLocation = adUseClient
rs.Open sql,conn,0,1,1
rs.ActiveConnection = Nothing
------------------------------------------------------------------------------
9. 간이트랜젝션 사용하기
여러가지 상황에서 트랜젝션이 필요한 경우가 많다.
특히 insert나 update등은 한번에 여러개의 테이블에 안전하게 데이터가 안착해야하는 케이스가 많은데, 
이런 경우 트랜젝션을 일일히 선언하거나, SP를 짠다는 것은 여간 귀찮은게 아니다.
가장 간단한 형태의 트랜젝션은 바로 쿼리문자열에 세미콜론으로 구분하여 한꺼번에 execute시키는 것이다.
아래와같은 형태가 된다.
strSQL="insert into a (a)values('바보');insert into b (b)values('너도')"
adoCn.execute strSQL,,1+&H80
이러한 구문은 MSsql2000에서 지원되고 저 두개의 쿼리를 하나의 트랜젝션으로 취급해준다.
------------------------------------------------------------------------------
10. ADOR객체를 사용하기
ADODB 객체에는 오만가지 객체가 포함되어있다(Connect,Command,Recordset,Record,Stream)
단지 레코드셋이 필요한데 저런게 다 필요하단말인가(게다가 단일 연결을 한번만 하는 페이지의 경우는 디비
연결시 연결문자열로도 충분하다)
이런 경우 경량화객체인 ADOR객체를 사용하는 것이 좋다(대부분 언제나 좋다)
set rsOBJ = server.createobject("ADOR.Recordset")
dbconnSTR = "Provider=SQLOLEDB; Data Source=서버이름;..."
sqlSTR = "select * from test"
rsOBJ.open sqlSTR, dbconnSTR, 0, 1,1
머 위와같은 정도로 사용하면 될듯. 근데 이상하게 이 객체에 대해서 다루는 책자는 드물다. 록스책중에 하나 
있긴한데..
------------------------------------------------------------------------------
[출처] [펌] asp에서 디비작업 최적화하기|작성자 수유산장


출처 - http://blog.naver.com/falconer00/80005961037
Posted by 알찬돌삐

댓글을 달아 주세요



윈도우 NT 와 2000 에서 간단하게 메일 발송하는 방법입니다.








  1.  set mm = server.CreateObject("cdonts.newmail")
  2.  mm.to = "xxx@xxx.com"   ' 받는 이메일
  3.  mm.from = "xxx@xxx.com" ' 보내는 이메일
  4.  mm.cc = ""              ' 참조  
  5.  mm.bcc = ""             ' 숨은참조
  6.  mm.subject = "제목"      ' 제목
  7.  mm.mailformat = 0
  8.  mm.bodyformat = 0
  9.  mm.importance = 0
  10.  mm.body = mbody
  11.  mm.send
  12.  set mm = nothing



Posted by 알찬돌삐

댓글을 달아 주세요