'연구개발 > SQL2005' 카테고리의 다른 글
DML 트리거의 사용 (0) | 2009.06.15 |
---|---|
커서 정보 확인 (0) | 2009.06.12 |
시스템 저장 프로시저(Transact-SQL) (0) | 2009.06.11 |
저장된 프로시저의 이름 및 내용 확인 (0) | 2009.06.11 |
잠금정보 확인 (0) | 2009.06.10 |
DML 트리거의 사용 (0) | 2009.06.15 |
---|---|
커서 정보 확인 (0) | 2009.06.12 |
시스템 저장 프로시저(Transact-SQL) (0) | 2009.06.11 |
저장된 프로시저의 이름 및 내용 확인 (0) | 2009.06.11 |
잠금정보 확인 (0) | 2009.06.10 |
SQL Server에서는 시스템 저장 프로시저를 통해 다양한 관리 및 정보 작업 수행할 수 있습니다. 시스템 저장 프로시저는 다음 표에 표시된 범주별로 그룹화됩니다.
범주 | 설명 |
---|---|
SQL Server 인스턴스 및 SQL Server 데이터베이스를 Microsoft Windows 2000 Active Directory에 등록합니다. | |
ODBC 데이터 사전 기능을 구현하고 ODBC 응용 프로그램을 원본 시스템 테이블 변경으로부터 격리합니다. | |
변경 데이터 캡처 개체를 사용하도록 설정 또는 해제하거나 해당 개체에 대해 보고합니다. | |
커서 변수 기능을 구현합니다. | |
SQL Server 데이터베이스 엔진의 일반적인 유지 관리에 사용됩니다. | |
SQL Server 인스턴스 내의 전자 메일 작업을 수행합니다. | |
데이터베이스 성능을 관리하는 데 필요한 주요 유지 관리 태스크를 설정합니다. | |
분산 쿼리를 구현하고 관리합니다. | |
전체 텍스트 인덱스를 구현하고 쿼리합니다. | |
로그 전달 구성을 구성, 수정 및 모니터링합니다. | |
표준 Transact-SQL 일괄 처리에서 표준 자동화 개체를 사용할 수 있도록 합니다. | |
복제를 관리합니다. | |
보안을 관리합니다. | |
SQL Server 프로파일러에서 성능 및 작업을 모니터링하는 데 사용합니다. | |
SQL Server 에이전트가 예약된 이벤트 기반 작업을 관리하는 데 사용합니다. | |
XML 텍스트 관리에 사용합니다. | |
다양한 유지 관리 작업을 위해 SQL Server 인스턴스에서 외부 프로그램으로의 인터페이스를 제공합니다. |
![]() |
---|
특별히 지정되지 않는 한 모든 시스템 저장 프로시저는 성공을 의미하는 값 0을 반환합니다. 실패에 대해서는 0이 아닌 값이 반환됩니다. |
ADO, OLE DB 및 ODBC 응용 프로그램에 대해 SQL Server 프로파일러를 실행하는 사용자는 이러한 응용 프로그램이 Transact-SQL 참조에서 다루지 않는 시스템 저장 프로시저를 사용한다는 사실을 알 수 있습니다. 이러한 저장 프로시저는 Microsoft SQL Server 네이티브 클라이언트 OLE DB 공급자 및 SQL Server 네이티브 클라이언트 ODBC 드라이버에서 데이터베이스 API 기능을 구현하는 데 사용합니다. 이러한 저장 프로시저는 사용자 요청을 SQL Server에 전달하기 위해 공급자 또는 드라이버가 사용하는 메커니즘으로 공급자 또는 드라이버에서 내부적으로만 사용하도록 되어 있습니다. SQL Server 기반 응용 프로그램에서 이들을 명시적으로 호출할 수는 없습니다.
SQL Server 기반 응용 프로그램은 이러한 저장 프로시저가 지원하는 API 기능을 통해 그 기능을 완전하게 이용할 수 있습니다. 예를 들어 sp_cursor 시스템 저장 프로시저의 커서 기능은 OLE DB API 커서 속성 및 메서드를 통해 OLE DB 응용 프로그램에 사용할 수 있으며 ODBC 커서 특성 및 함수를 통해서는 ODBC 응용 프로그램에 사용할 수 있습니다.
다음 저장 프로시저는 ADO, OLE DB 및 ODBC의 커서 기능을 지원합니다.
sp_cursor |
sp_cursorclose |
sp_cursorexecute |
sp_cursorfetch |
sp_cursoropen |
sp_cursoroption |
sp_cursorprepare |
sp_cursorunprepare |
|
다음 시스템 저장 프로시저는 ADO, OLE DB, ODBC에서 Transact-SQL 문을 실행하는 준비/실행 모델을 지원합니다.
sp_execute |
sp_prepare |
sp_unprepare |
sp_createorphan 및 sp_droporphans 저장 프로시저는 ODBC ntext, text 및 image 처리에 사용됩니다.
sp_reset_connection 저장 프로시저는 SQL Server에서 트랜잭션의 원격 저장 프로시저 호출을 지원하는 데 사용됩니다. 이 저장 프로시저는 연결 풀에서 연결이 다시 사용될 때 Audit Login 및 Audit Logout 이벤트도 실행합니다.
다음 표에 있는 시스템 저장 프로시저는 SQL Server 인스턴스 내부 또는 클라이언트 API를 통해서만 사용되며 일반적인 용도로는 사용되지 않습니다. 이 표의 내용은 변경될 수 있으며 호환성을 보장하지 않습니다.
다음 저장 프로시저는 SQL Server 온라인 설명서에 문서화되어 있습니다.
sp_catalogs |
sp_column_privileges |
sp_column_privileges_ex |
sp_columns |
sp_columns_ex |
sp_databases |
sp_datatype_info |
sp_fkeys |
sp_foreignkeys |
sp_indexes |
sp_pkeys |
sp_primarykeys |
sp_server_info |
sp_special_columns |
sp_sproc_columns |
sp_statistics |
sp_table_privileges |
sp_table_privileges_ex |
sp_tables |
sp_tables_ex |
다음 저장 프로시저는 문서화되어 있지 않습니다.
sp_assemblies_rowset |
sp_assemblies_rowset_rmt |
sp_assemblies_rowset2 |
sp_assembly_dependencies_rowset |
sp_assembly_dependencies_rowset_rmt |
sp_assembly_dependencies_rowset2 |
sp_bcp_dbcmptlevel |
sp_catalogs_rowset |
sp_catalogs_rowset;2 |
sp_catalogs_rowset;5 |
sp_catalogs_rowset_rmt |
sp_catalogs_rowset2 |
sp_check_constbytable_rowset |
sp_check_constbytable_rowset;2 |
sp_check_constbytable_rowset2 |
sp_check_constraints_rowset |
sp_check_constraints_rowset;2 |
sp_check_constraints_rowset2 |
sp_column_privileges_rowset |
sp_column_privileges_rowset;2 |
sp_column_privileges_rowset;5 |
sp_column_privileges_rowset_rmt |
sp_column_privileges_rowset2 |
sp_columns_90 |
sp_columns_90_rowset |
sp_columns_90_rowset_rmt |
sp_columns_90_rowset2 |
sp_columns_ex_90 |
sp_columns_rowset |
sp_columns_rowset;2 |
sp_columns_rowset;5 |
sp_columns_rowset_rmt |
sp_columns_rowset2 |
sp_constr_col_usage_rowset |
sp_datatype_info_90 |
sp_ddopen;1 |
sp_ddopen;10 |
sp_ddopen;11 |
sp_ddopen;12 |
sp_ddopen;13 |
sp_ddopen;2 |
sp_ddopen;3 |
sp_ddopen;4 |
sp_ddopen;5 |
sp_ddopen;6 |
sp_ddopen;7 |
sp_ddopen;8 |
sp_ddopen;9 |
sp_foreign_keys_rowset |
sp_foreign_keys_rowset;2 |
sp_foreign_keys_rowset;3 |
sp_foreign_keys_rowset;5 |
sp_foreign_keys_rowset_rmt |
sp_foreign_keys_rowset2 |
sp_foreign_keys_rowset3 |
sp_indexes_90_rowset |
sp_indexes_90_rowset_rmt |
sp_indexes_90_rowset2 |
sp_indexes_rowset |
sp_indexes_rowset;2 |
sp_indexes_rowset;5 |
sp_indexes_rowset_rmt |
sp_indexes_rowset2 |
sp_linkedservers_rowset |
sp_linkedservers_rowset;2 |
sp_linkedservers_rowset2 |
sp_oledb_database |
sp_oledb_defdb |
sp_oledb_deflang |
sp_oledb_language |
sp_oledb_ro_usrname |
sp_primary_keys_rowset |
sp_primary_keys_rowset;2 |
sp_primary_keys_rowset;3 |
sp_primary_keys_rowset;5 |
sp_primary_keys_rowset_rmt |
sp_primary_keys_rowset2 |
sp_procedure_params_90_rowset |
sp_procedure_params_90_rowset2 |
sp_procedure_params_rowset |
sp_procedure_params_rowset;2 |
sp_procedure_params_rowset2 |
sp_procedures_rowset |
sp_procedures_rowset;2 |
sp_procedures_rowset2 |
sp_provider_types_90_rowset |
sp_provider_types_rowset |
sp_schemata_rowset |
sp_schemata_rowset;3 |
sp_special_columns_90 |
sp_sproc_columns_90 |
sp_statistics_rowset |
sp_statistics_rowset;2 |
sp_statistics_rowset2 |
sp_stored_procedures |
sp_table_constraints_rowset |
sp_table_constraints_rowset;2 |
sp_table_constraints_rowset2 |
sp_table_privileges_rowset |
sp_table_privileges_rowset;2 |
sp_table_privileges_rowset;5 |
sp_table_privileges_rowset_rmt |
sp_table_privileges_rowset2 |
sp_table_statistics_rowset |
sp_table_statistics_rowset;2 |
sp_table_statistics2_rowset |
sp_tablecollations |
sp_tablecollations_90 |
sp_tables_info_90_rowset |
sp_tables_info_90_rowset_64 |
sp_tables_info_90_rowset2 |
sp_tables_info_90_rowset2_64 |
sp_tables_info_rowset |
sp_tables_info_rowset;2 |
sp_tables_info_rowset_64 |
sp_tables_info_rowset_64;2 |
sp_tables_info_rowset2 |
sp_tables_info_rowset2_64 |
sp_tables_rowset;2 |
sp_tables_rowset;5 |
sp_tables_rowset_rmt |
sp_tables_rowset2 |
sp_usertypes_rowset |
sp_usertypes_rowset_rmt |
sp_usertypes_rowset2 |
sp_views_rowset |
sp_views_rowset2 |
sp_xml_schema_rowset |
sp_xml_schema_rowset2 |
|
커서 정보 확인 (0) | 2009.06.12 |
---|---|
테이블 필드명 변경 (0) | 2009.06.12 |
저장된 프로시저의 이름 및 내용 확인 (0) | 2009.06.11 |
잠금정보 확인 (0) | 2009.06.10 |
index 체크 유무 (0) | 2009.06.08 |
테이블 필드명 변경 (0) | 2009.06.12 |
---|---|
시스템 저장 프로시저(Transact-SQL) (0) | 2009.06.11 |
잠금정보 확인 (0) | 2009.06.10 |
index 체크 유무 (0) | 2009.06.08 |
조직도 나타내기 - 재귀적호출 (0) | 2009.05.26 |
시스템 저장 프로시저(Transact-SQL) (0) | 2009.06.11 |
---|---|
저장된 프로시저의 이름 및 내용 확인 (0) | 2009.06.11 |
index 체크 유무 (0) | 2009.06.08 |
조직도 나타내기 - 재귀적호출 (0) | 2009.05.26 |
여러 로우의 값을 하나의 컬럼으로 바꾸는 방법 (0) | 2009.05.20 |
저장된 프로시저의 이름 및 내용 확인 (0) | 2009.06.11 |
---|---|
잠금정보 확인 (0) | 2009.06.10 |
조직도 나타내기 - 재귀적호출 (0) | 2009.05.26 |
여러 로우의 값을 하나의 컬럼으로 바꾸는 방법 (0) | 2009.05.20 |
프로시저에서 중첩된 프로시저 실행 후 트랜잭션 처리될 때 (0) | 2009.05.19 |
재귀적이란 자기 자신을 호출하는 것을 말한다.
USE sqlDB
GO
CREATE TABLE empTbl (emp NCHAR(3), manager NCHAR(3), department NCHAR(3))
GO
INSERT INTO empTbl VALUES ('나사장', NULL, NULL)
INSERT INTO empTbl VALUES ('김재무', '나사장', '재무부')
INSERT INTO empTbl VALUES ('김부장', '김재무', '재무부')
INSERT INTO empTbl VALUES ('이부장', '김재무', '재무부')
INSERT INTO empTbl VALUES ('우대리', '이부장', '재무부')
INSERT INTO empTbl VALUES ('지사원', '이부장', '재무부')
INSERT INTO empTbl VALUES ('이영업', '나사장', '영업부')
INSERT INTO empTbl VALUES ('한과장', '이영업', '영업부')
INSERT INTO empTbl VALUES ('최정보', '나사장', '정보부')
INSERT INTO empTbl VALUES ('윤차장', '최정보', '정보부')
INSERT INTO empTbl VALUES ('이주임', '윤차장', '정보부')
SELECT * FROM empTbl;
WITH empCTE (empName, mgrName, dept, level)
AS
(
SELECT emp, manager, department, 0
FROM empTbl
WHERE manager IS NULL --상관이 없는 사람이 바로 사장
UNION ALL
SELECT AA.emp, AA.manager, AA.department, BB.level+1
FROM empTbl AS AA INNER JOIN empCTE AS BB
ON AA.manager = BB.empName
)
SELECT * FROM empCTE ORDER BY dept, level;
--수정
WITH empCTE (empName, mgrName, dept, level)
AS
(
SELECT emp, manager, department, 0
FROM empTbl
WHERE manager IS NULL --사장
UNION ALL
SELECT AA.emp, AA.manager, AA.department, BB.level + 1
FROM empTbl AS AA INNER JOIN empCTE AS BB
ON AA.manager = BB.empName
)
SELECT replicate(' ', level) + '*' + empName AS [직원이름], dept AS [직원부서]
FROM empCTE ORDER BY dept, level
잠금정보 확인 (0) | 2009.06.10 |
---|---|
index 체크 유무 (0) | 2009.06.08 |
여러 로우의 값을 하나의 컬럼으로 바꾸는 방법 (0) | 2009.05.20 |
프로시저에서 중첩된 프로시저 실행 후 트랜잭션 처리될 때 (0) | 2009.05.19 |
LDF 파일 용량 축소 (0) | 2009.05.17 |
index 체크 유무 (0) | 2009.06.08 |
---|---|
조직도 나타내기 - 재귀적호출 (0) | 2009.05.26 |
프로시저에서 중첩된 프로시저 실행 후 트랜잭션 처리될 때 (0) | 2009.05.19 |
LDF 파일 용량 축소 (0) | 2009.05.17 |
MS-SQL 페이징 쿼리 종류별 성능 비교 (0) | 2009.04.24 |
index 체크 유무 (0) | 2009.06.08 |
---|---|
조직도 나타내기 - 재귀적호출 (0) | 2009.05.26 |
여러 로우의 값을 하나의 컬럼으로 바꾸는 방법 (0) | 2009.05.20 |
LDF 파일 용량 축소 (0) | 2009.05.17 |
MS-SQL 페이징 쿼리 종류별 성능 비교 (0) | 2009.04.24 |
index 체크 유무 (0) | 2009.06.08 |
---|---|
조직도 나타내기 - 재귀적호출 (0) | 2009.05.26 |
여러 로우의 값을 하나의 컬럼으로 바꾸는 방법 (0) | 2009.05.20 |
프로시저에서 중첩된 프로시저 실행 후 트랜잭션 처리될 때 (0) | 2009.05.19 |
MS-SQL 페이징 쿼리 종류별 성능 비교 (0) | 2009.04.24 |
= Include 파일 =
① top.inc <table width=100% ID="Table1" height="100%"> <tr> <td>회사로고</td> </tr> </table> ② copyright.inc <table width=100% ID="Table1" height="100%"> <tr> <td>Copyright</td> </tr> </table> |
= 일반 페이지 =
<table border=1 width = 80% height=90%> <tr> <td> <!-- #include file = "./Include/top.inc" --> </td> </tr> <tr height=80%> <td>페이지별 내용(Inlude 페이지)</td> </tr> <tr> <td> <!-- #include file = "./Include/copyright.inc" --> </td> </tr> </table> |
2. 웹 UserControl 방식
- .NET 은 웹사이트의 이러한 요구사항을 위한 해결책으로 UserControl 이라는 걸 지원하게 되었다.
큰 흐름은 Include 방식과 유사하나 .NET 의 특성을 그대로 계승한 형태로 진화 되었다.
공통부분을 별도의 UserControl로 생성한 후 이 컨트롤을 모든 페이지에 Register(등록) 시키는 방법이다
다음 샘플코드는 top.ascx, copyright.ascx 라는 UserControl파일을 생성한 후 일반 페이지에서 등록 하는 코드이다.
= UserControl 파일 =
① top.ascx <%@ Control Language="c#" AutoEventWireup="false" Codebehind="top.ascx.cs" Inherits="WebApplication1.UserControl.top" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%> <table width=100% ID="Table1" height="100%"> <tr> <td>회사로고</td> </tr> </table> ② copyright.inc <%@ Control Language="c#" AutoEventWireup="false" Codebehind="copyright.ascx.cs" Inherits="WebApplication1.UserControl.copyright" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%> <table width=100% ID="Table1" height="100%"> <tr> <td>Copyright</td> </tr> </table> |
= 일반 페이지 =
… <%@ Register TagPrefix="uc1" TagName="top" Src="UserControl/top.ascx" %> <%@ Register TagPrefix="uc1" TagName="copyright" Src="UserControl/copyright.ascx" %> … <table border="1" width="80%" height="90%"> <tr> <td> <uc1:top id="Top1" runat="server"></uc1:top> </td> </tr> <tr height="80%"> <td>페이지별 내용(UserControl 페이지)</td> </tr> <tr> <td> <uc1:copyright id="Copyright1" runat="server"></uc1:copyright> </td> </tr> </table>
3. HttpModule 방식
- 조금은 생소할 수도 있으나 닷넷의 요청과 응답사이에 ISAPI 필터처럼 동작하는 HttpModule 로도 이와 같은 공통처리를 할 수도 있다.
물론 HttpModule 가 UI 의 공통요소를 처리하기 위한 메터니즘과는 어울리지 않는다(일종의 필터라고 생각하면 된다)
그러나 이번 글에서는 이러한 방식도 있다는 차원에서 언급하도록 한다.
동작방식을 간략히 설명하자면,
요청의 처음과 끝에 개입하여 특정 로직을 수행하도록 하는데 이 부분에 공통 UI 를 기술하게 된다.
다음 샘플코드는 IHttpModule 를 구현하는 CustomHttpModule 클래스를 만들고 이 모듈이 모든 페이지 요청에 개입하도록 하는 코드이다.
= CustomerHttpModule 클래스 =
public class CustomHttpModule : IHttpModule { public CustomHttpModule(){} public void Init(HttpApplication context) { context.BeginRequest += (new EventHandler(this.Application_BeginRequest)); context.EndRequest += (new EventHandler(this.Application_EndRequest)); } public void Application_BeginRequest(object sender,EventArgs e) { HttpApplication application = (HttpApplication)sender; HttpContext context = application.Context; context.Response.Write("<table width=80% border=1><tr><td>회사로고</td></tr></table>"); } public void Application_EndRequest(object sender,EventArgs e) { HttpApplication application = (HttpApplication)sender; HttpContext context = application.Context; context.Response.Write("<table width=80% border=1><tr><td>Copyright</td></tr></table>"); } } |
= Web.Config 설정=
<httpModules> <add name="CustomHttpModule" type="WebApplication1.CustomHttpModule, WebApplication1" /> </httpModules> = Master 페이지 = <%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %> … <table border="1" width="80%" height="90%"> <tr> <td> <table width="100%" height="100%"> <tr> <td>회사로고</td> </tr> </table> </td> </tr> <tr height="300"> <td > <asp:contentplaceholder id="ContentPlaceHolder1" runat="server"> </asp:contentplaceholder> </td> </tr> <tr> <td> <table width="100%" height="100%"> <tr> <td>Copyright</td> </tr> </table> </td> </tr> </table> = 일반 페이지 =
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" Title="Untitled Page" %> <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> 페이지별 내용(일반 페이지) </asp:Content>
첨부파일에 이 글에서 사용된 샘플코드가 포함되어 있다.
4. MasterPage 방식(닷넷 2.0 에 새로 추가된 기능)
- 드디어 주인공이 등장한다. 이전까지의 액스터라들은 MasterPage 를 위한 들러리(?)일 뿐이었다 --;
닷넷 2.0 에서는 보다 근본적인 해결책과 다른 접근 방법으로 이와 같은 요구사항을 충족시키는 매커니즘을 새로 내놓았다.
이것이 바로 Master Page 라는 것이다.
Master Page 는 이전 방법들과는 다른 접근 방법을 채택하고 있따.
이전 방식에서는 공통되는 부분을 별도로 분리하여 모든 페이지에 명시적으로 포함하도록 코딩했었다.
그러나 Master Page 에서는 주/객이 바뀌었다고 보면 된다.
Master Page 가 전체 골격을 유지하며 공통요소를 포함하게 되며 일반페이지들은 이 Master Page 를 Content 페이지로써 동작하도록 한다.
다음 샘플코드는 MasterPage.master 이라는 마스터 페이지를 정의하고 Content 로 생성되는 일반페이지에 대한 코드 이다.
ASP.NET AJAX로 만드는 RSS Viewer - Part2 [ASP.NET] (0) | 2009.06.16 |
---|---|
ASP.NET AJAX로 만드는 RSS Viewer - Part1 [ASP.NET] (0) | 2009.06.16 |
Cookie 제대로 알고 사용하자 (0) | 2009.04.24 |
System.Security.SecurityException: 요청한 레지스트리에 액세스할 수 없습니다 (0) | 2009.04.24 |
ASP.NET에서 다중쿠키 수정시 주의점 (0) | 2009.04.24 |
『 Cookie 제대로 알고 사용하자 』
Cookie 는 아주 보편적이고 유명(?)하기 까지 하다.
웹 개발자는 물론이고 일반 웹 유저들 마저 쿠키에 대해 어느 정도는 알고 있다.
비 연결 지향인 웹 환경에서 사용자(일반적으로 웹 브라우저가 되겠다)와 웹 서버간의 특정 데이터의 상태 정보 저장을 위해 사용하는 하나의 기법이다.
이번 아티클은 이렇게 보편적인 쿠키를 개발단에서 사용할 때 참고할 만한 내용들을 정리해 본다.
1. 쿠키는 어디에 저장되는가?
일반적으로 쿠키는 아래의 경로에 TXT 파일 형태로 저장이 된다.
‘C:\Documents and Settings\현재로그인한 사용자\Cookies’
그러나 서버에서 쿠키의 만료 일자를 지정하지 않았다면 파일로 저장되지 않고 사용자 세션정보의 일부로써 유지된다.
즉 브라우저 기반 쿠키로써 브라우저를 닫으면 쿠키 역시 소멸되는 것이다
쿠키를 파일로 저장하지 않는 것은 보안상 이슈로 더 좋은 선택이 될 수 있다.
결론적으로, 쿠키를 설정할 때 만료일자의 지정 유/무에 따라 파일기반 쿠키 또는 세션(브라우저)기반 쿠키로 저장되는 것이다
참고> 만일 파일기반 쿠키의 경우 동일한 이름의 쿠키를 저장할 경우 이전 쿠키파일을 덮어 쓰게 된다
2. 쿠키의 제한 사항
웹 서버가 클라이언트에게 쿠키를 저장 할 경우 대부분 아래와 같은 제약 사항을 가진다.
1) 하나의 사이트에서 클라이언트에게 저장할 수 있는 최대 쿠키는 20개까지 이다.
2) 최대 4096 byte 쿠키 지원
쿠키의 수적 제한과 최대 크기의 제한 사항은 하위키 형태의 쿠키로 해결 할 수 있다.
즉, 만일 한 사이트에서 20개 이상의 쿠키가 필요하다면 하위 키를 포함한 쿠키를 사용하면 더 많은 쿠키를 저장하는 효과를 볼 수 있다.
Cookie[“Key”][“하위키1”]; Cookie[“Key”][“하위키2”];
이에 대한 MSDN 내용은 다음과 같다.
하위 키를 포함하는 쿠키를 사용하면 쿠키 파일의 크기를 제한하는 데에도 도움이 됩니다. 일반적으로 쿠키는 4096바이트로 제한되고 각 사이트마다 최대 20개의 쿠키를 저장할 수 있습니다. 하위 키를 포함하는 단일 쿠키를 사용하면 사이트에 할당된 20개의 쿠키보다 적은 수의 쿠키를 사용하게 됩니다. 또한 단일 쿠키에는 오버헤드(만료 정보 등)에 대한 50개 정도의 문자와 쿠키에 저장되는 값의 길이가 포함됩니다. 이 값은 모두 4096바이트 제한에 거의 근접한 값입니다. 5개의 쿠키를 개별적으로 저장하는 대신 하위 키 5개를 저장하면 개별 쿠키로 인한 오버헤드를 줄여 약 200바이트를 절약할 수 있습니다. |
3. 쿠키 샘플
이제 ASP.NET 에서 쿠키를 저장하고 불러오는 샘플 코드를 보자.
1) 쿠키 저장하기
아래 샘플 코드는 하위키를 가진 쿠키를 저장하는 두 가지 방법을 나타낸다
Response.Cookies["MyCookie"]["Cookie1"] = "값1"; Response.Cookies["MyCookie "][" Cookie2"] = “값2”; Response.Cookies["MyCookie "].Expires = DateTime.Now.AddDays(1); HttpCookie aCookie = new HttpCookie("MyCookie "); aCookie.Values["Cookie1"] = " 값1"; aCookie.Values["Cookie2"] = “값2” aCookie.Expires = DateTime.Now.AddDays(1); Response.Cookies.Add(aCookie); |
2) 쿠키 불러오기
아래 샘플 코드는 하위키를 가진 쿠키를 불러오는 방법을 나타낸다
샘플 처럼 해당 쿠키가 존재하는지 여부를 체크 하는 것이 좋다.(그렇지 않으면 ‘NullReferenceException’ 이 발생할 수 있다)
if(Request.Cookies["MyCookie "] != null) { Label1.Text = Server.HtmlEncode(Request.Cookies["MyCookie "][" Cookie1"]); Label2.Text = Server.HtmlEncode(Request.Cookies["MyCookie "][" Cookie2"]); } |
MSDN : 쿠키 값을 표시하기 전에 HtmlEncode 메서드를 호출하여 쿠키 내용을 인코딩했습니다. 이렇게 하면 악의적인 사용자가 실행 스크립트를 쿠키에 추가할 수 없습니다.
3) 모든 쿠키 읽기
현재 나의 사이트에서 저장한 모든 쿠키를 알아 볼 수 있는 샘플 코드이다. (MSDN)
for(int i=0; i<Request.Cookies.Count; i++) { aCookie = Request.Cookies[i]; output.Append("Name = " + aCookie.Name + "<br />"); if(aCookie.HasKeys) { for(int j=0; j<aCookie.Values.Count; j++) { subkeyName = Server.HtmlEncode(aCookie.Values.AllKeys[j]); subkeyValue = Server.HtmlEncode(aCookie.Values[j]); output.Append("Subkey name = " + subkeyName + "<br />"); output.Append("Subkey value = " + subkeyValue + "<br /><br />"); } } else { output.Append("Value = " + Server.HtmlEncode(aCookie.Value) + "<br /><br />"); } } Label1.Text = output.ToString(); |
4. 쿠키 (유효) 범위 제어
쿠키를 저장 하고 난 후 사용할 때 (불러올 때) 에 유요한 범위를 아래와 같이 두 가지 방법으로 제어 할 수 있다.
1) 디렉터리 단위 제어
웹 서버의 특정 디렉터리(폴더)를 기준으로 쿠키의 범위를 제어 할 수 있다.
ASP.NET 의 HttpCookie 에는 Path 속성이 이와 관련된 속성이다.
만일 Path = “/Directory1” 로 설정된 쿠키라면 웹 서버의 ‘/Directory1’ 의 하위 폴더 및 가상 디렉터리에서만 쿠키 값을 읽어 들일 수 있게 되는 것이다.
이외의 폴더 및 루트에 속한 페이지에서는 쿠키를 사용할 수 없다.
Path 속성이 설정되지 않으면 기본적으로 웹 루트인 ‘/’ 가 설정되므로 해당 웹 사이트에서는 모두 사용 가능하게 되는 것이다.
참고> 일부 브라우저 에서는 경로의 대/소문자를 구분한다. 즉 URL 과 Path 속성이 정확히 대/소문자가 일치해야 쿠키를 사용할 수 있다.
2) 도메인 단위 제어
도메인 단위로도 범위 설정이 가능하다.
만일 특정 하위 도메인 에서만 사용가능한 쿠키를 만들고 싶으면 Domain 속성을 지정해 주면 된다.
Mkexp.pe.kr 사이트의 하위 도메인인 sub.mkex.pe.kr 에서만 쿠키를 사용하고 싶으면 Domain = “sub.mkex.pe.kr” 로 설정하면 된다.
또한 mkex.pe.kr 의 모든 하위도메인에서 사용가능 한 쿠키를 만들고 싶으면 Domain = “mkex.pe.kr” 로 설정하면 된다
5. 쿠키 허용 유/무
클라이언트는 서버에서 제공하는 쿠키를 허용할 지 결정 할 수있다.
아래 그림은 IE 6.0 에서 쿠키를 차단하는 모습니다.
이렇게 되면 웹 서버에서 쿠키를 사용하고 싶어도 할 수 없다.
단, 웹 서버에 쿠키 저장 시 오류는 발생하지 않는다. 다만 클라이언트는 쿠키를 저장하지 않으며 서버 요청 시 쿠키 값도 전달하지 않는 것이다.
따라서 쿠키 의존도가 상당히 강한 사이트의 경우 클라이언트의 쿠키 허용 유/무를 판단할 필요가 있다.
그러나 클라이언트의 브라우저가 쿠키를 허용 했는지 안 했는지 한방에 체크 할 수는 없다.
Msdn : Cookies 속성은 쿠키 사용 여부를 나타내지 않습니다. 대신 현재 브라우저에서 기본적으로 쿠키를 지원하는지 여부만 나타냅니다.
따라서 msdn 에서 이를 체크 하기 위해 조금은 무식한(?) 방법을 사용한다.
시나리오는 이렇다.
쿠키를 클라이언트에 저장해 한 후 다시 읽어 들여서 읽히면 쿠키가 허용된 것이고 아니면 쿠키가 불허용 된 것이라 판단하는 것이다.
아래는 msdn 의 샘플 코드이다.
//첫 번째 페이지(쿠키를 작성하고 두 번째 페이지로 리다이렉트 한다. protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { if (Request.QueryString["AcceptsCookies"] == null) { Response.Cookies["TestCookie"].Value = "ok"; Response.Cookies["TestCookie"].Expires = DateTime.Now.AddMinutes(1); Response.Redirect("TestForCookies.aspx?redirect=" + Server.UrlEncode(Request.Url.ToString())); } else { Label1.Text = "Accept cookies = " + Server.UrlEncode( Request.QueryString["AcceptsCookies"]); } } } //두 번째 페이지 (쿠키를 읽어보고 허용 유/무를 판단하여 다시 첫번째 페이지로 이동한다) protected void Page_Load(object sender, EventArgs e) { string redirect = Request.QueryString["redirect"]; string acceptsCookies; if(Request.Cookies["TestCookie"] ==null) acceptsCookies = "no"; else { acceptsCookies = "yes"; // Delete test cookie. Response.Cookies["TestCookie"].Expires = DateTime.Now.AddDays(-1); } Response.Redirect(redirect + "?AcceptsCookies=" + acceptsCookies, true); } |
Msdn 이 이러한 두 페이지에 걸친 처리보다는 클라이언트 스크립트로 처리하는 것이 더 좋을 때도 있다.
다음처럼…
<script language="JavaScript"> <!-- function ReadCookie(cookieName) { var theCookie=""+document.cookie; var ind=theCookie.indexOf(cookieName); if (ind==-1 || cookieName=="") return ""; var ind1=theCookie.indexOf(';',ind); if (ind1==-1) ind1=theCookie.length; return unescape(theCookie.substring(ind+cookieName.length+1,ind1)); } function SetCookie(cookieName,cookieValue,nDays) { var today = new Date(); var expire = new Date(); if (nDays==null || nDays==0) nDays=1; expire.setTime(today.getTime() + 3600000*24*nDays); document.cookie = cookieName+"="+escape(cookieValue) + ";expires="+expire.toGMTString(); } //--> </script> <script language="JavaScript"> <!-- testValue=Math.floor(1000*Math.random()); SetCookie('AreCookiesEnabled',testValue); if (testValue==ReadCookie('AreCookiesEnabled')) document.write('<b>현재고객님의 브라우져에는 쿠키가허용되어있습니다.</b>') else document.write('<b>현재 고객님의 브루우져에 쿠키허용이 금지되어있습니다. </b>') //--> </script> |
이 스크립트 코드는 asp.net 에서의 체크 시나리오와 동일하다. 단지 클라이언트에서 실행되는 것이라서 불 필요한 라운드 트립 이 발생하지 않는다는 장점이 있다.
샘플 코드의 해석은 중요치 않다. 단지 이러한 방법으로 확인하는 시나리오가 있을 수 있다는 것이 중요하다.
6. 기타 참고 사항
쿠키는 http 프로토콜의 헤더에 포함되어 진다.
아래 그림은 쿠키를 저장할 때의 http 헤더 정보이다.
자세한 http 헤더 정보는 다음 링크에서 확인 하자.
또한 하위 키가 있는 쿠키의 정보 변경 시 주의할 사항에 대해서는 다음 링크에서 확인 하자.
7. 쿠키.. 보안에 유의 하라.
쿠키는 정보 유지를 위해 클라이언트에 의존 하는 편하고도 좋은 방법이다.
그러나 모든 것은 얻는 것이 있으면 잃는 것 또한 있는 법이다.
기본적으로 쿠키는 클라이언트 pc에 txt 파일 형태로 저장되기 때문에 보안상 좋지 않다.
만일 중요한 정보를 평문 형태로 저장 한다면 이건 거의 자살행위나 마찬 가지다.
또한 적절한 암호화를 수행했다고 하여도 안정성은 보장 할 수 없다.
나아가 Key=Value 형태를 그대로 저장하는 것에도 문제가 있다.
가장 기본은 중요한 정보는 쿠키에 의존하면 안 된다 이다.
그러나 만일 불가피하게 약간은 중요한 정보를 쿠키에 저장해야만 할 경우에는 적절한 암호화를 수행하도록 한다.
또한 key=value 패턴을 사용하지 않도록 한다. 그리고 악의의 사용자가 특정 범위를 쉽게 알아내어 복호화 하는 것을 미연에 방지하도록 한다.
쿠키 변조와 관련된 내용은 아래 링크에서 확인 하자.
ASP.NET AJAX로 만드는 RSS Viewer - Part2 [ASP.NET] (0) | 2009.06.16 |
---|---|
ASP.NET AJAX로 만드는 RSS Viewer - Part1 [ASP.NET] (0) | 2009.06.16 |
페이지 공통 요소 분리하기 (0) | 2009.04.24 |
System.Security.SecurityException: 요청한 레지스트리에 액세스할 수 없습니다 (0) | 2009.04.24 |
ASP.NET에서 다중쿠키 수정시 주의점 (0) | 2009.04.24 |
ASP.NET AJAX로 만드는 RSS Viewer - Part2 [ASP.NET] (0) | 2009.06.16 |
---|---|
ASP.NET AJAX로 만드는 RSS Viewer - Part1 [ASP.NET] (0) | 2009.06.16 |
페이지 공통 요소 분리하기 (0) | 2009.04.24 |
Cookie 제대로 알고 사용하자 (0) | 2009.04.24 |
ASP.NET에서 다중쿠키 수정시 주의점 (0) | 2009.04.24 |
ASP.NET AJAX로 만드는 RSS Viewer - Part2 [ASP.NET] (0) | 2009.06.16 |
---|---|
ASP.NET AJAX로 만드는 RSS Viewer - Part1 [ASP.NET] (0) | 2009.06.16 |
페이지 공통 요소 분리하기 (0) | 2009.04.24 |
Cookie 제대로 알고 사용하자 (0) | 2009.04.24 |
System.Security.SecurityException: 요청한 레지스트리에 액세스할 수 없습니다 (0) | 2009.04.24 |
mkex.pe.kr 에 '허동석' 님이 작성해 주신 글을 옮겨 옵니다.
---------------------------------------------------------------------------------------------------------------------------------------
페이징 쿼리 종류별로 성능을 비교한 좋은 자료가 있어서 상당부분 인용했습니다.
"ex)"에 들어가는 샘플 쿼리는 바투 락커룸 DB에 파일첨부(TB_AttachFile) 테이블을 대상으로 페이징 쿼리를 작성해 봤습니다.
5번에 표시된 내용이 데이터 건수에 상관없이 실질적으로 가장 빠르지만 우리 시스템에 적용할 수 있는지는 의문이 갑니다. 테이블 별로 인덱스 생성이 필요할 수 있고 중간에 데이터가 삭제되거나 어떤 반응이 생길 때 문제가 될 소지가 있는지도 조사해야 할 것 같습니다.
참고로 웹젠 빌링에서 사용하던 페이징 쿼리는 4번을 이용했었습니다.
그리고 2번에 샘플 쿼리를 보면 TB_AttachFile 테이블에 FileGuid가 None Clustered Index로 걸려 있어서 서브쿼리 내에서도 ORDER BY FileGuid DESC를 해줘야합니다.(즉 ORDER BY 를 2번 해야한다는..)
대부분의 기본키들이 None Clustered Index 라 이 점에 대한 이슈도 있습니다.
1. SELECT TOP [불러올 총 게시물수] [출력 필드명] FROM [테이블 명]
레코드셋의 AbsolutePage를 이용해서 페이징을 했습니다.
ex)
SELECT TOP 10 FileGuid, FileName, Capacity, RegDate
FROM TB_AttachFile
2. SELECT TOP [불러올 총 게시물수] [출력 필드명] FROM [테이블 명]
WHERE [글번호필드] NOT IN (SELECT TOP [제거할 게시물수] [글번호필드] FROM [테이블명])
예전에 태요 사이트에서 보았던 쿼리 구문입니다.. NOT IN 때문에.. 문제시 되었던 쿼리구문이죠.
ex)
SELECT TOP 10 FileGuid, FileName, Capacity, RegDate
FROM TB_AttachFile
WHERE FileGuid NOT IN
(
SELECT TOP 0 FileGuid
FROM TB_AttachFile
ORDER BY FileGuid DESC
)
ORDER BY FileGuid DESC
3. SELECT TOP [불러올 총 게시물수] [출력 필드명] FROM [테이블 명]
WHERE [글번호] IN (SELECT TOP [페이지출력 갯수] [글번호] FROM
(SELECT TOP [불러올 총 게시물수] [글번호] FROM [테이블 명]) AS A ORDER BY [글번호])
ORDER BY [글번호] DESC
이 쿼리 구문은 2번의 쿼리 구문의 문제점을 보완한 구문입니다. NOT IN 대신에 IN을 사용 했습니다.
ex)
SELECT TOP 10 FileGuid, FileName, Capacity, RegDate
FROM TB_AttachFile
WHERE FileGuid IN
(
SELECT TOP 123 FileGuid -- 총 데이터수 - ( (페이지수 - 1) * 10) // 1페이지 : 123 - 0, 2페이지 : 123 - 10 ...
FROM
(
SELECT FileGuid
FROM TB_AttachFile
)AS A
ORDER BY FileGuid
)
ORDER BY FileGuid DESC
4. SELECT TOP [페이지 출력갯수] [출력 필드명] FROM [테이블 명]
WHERE [글번호] <= (SELECT MIN([글번호])
FROM (SELECT TOP [제거할 게시물수] + 1 [글번호] FROM [테이블명]) AS A)
4번째 쿼리 구문은 IN, NOT IN이 아닌 출력할 마지막 글번호 바로 앞이 글번호를 찾아서 처리를 해주는
쿼리 구문입니다.
ex)
SELECT TOP 10 FileGuid, FileName, Capacity, RegDate
FROM TB_AttachFile
WHERE FileGuid <=
(
SELECT MIN(FileGuid)
FROM
(
SELECT TOP 11 FileGuid -- (현재페이지수-1) * 10 + 1
FROM TB_AttachFile
ORDER BY FileGuid DESC
)AS A
)
ORDER BY FileGuid DESC
5. SELECT TOP [페이지 출력갯수] [출력 필드명] FROM [테이블명]
WHERE [글번호] <= (SELECT MIN([글번호])
FROM (SELECT TOP [제거할 게시물수] + 1 [글번호]
FROM [테이블명] WHERE [인덱스] = [시작인덱스번호] AND [인덱스] = [끝인덱스번호]) AS A
WHERE [인덱스] = [시작인덱스번호] AND [인덱스] = [끝인덱스번호])
AND [인덱스] = [시작인덱스번호] AND [인덱스] = [끝인덱스번호]
5번재 쿼리는.. 글에 인덱스(가칭)라는 필드를 하나 더 추가 해서.. 글 기본 2000개마다 (가변적입니다)
인덱스를 증가 시켰습니다. 즉 2000개를 하나의 묶음으로 만든것입니다.
그 인덱스를 기준으로 처리를 해주었습니다.
ex)
SELECT TOP 10 FileGuid, FileName, Capacity, RegDate
FROM TB_AttachFile
WHERE FileGuid <=
(
SELECT MIN(FileGuid)
FROM
(
SELECT TOP 11 FileGuid -- (현재페이지수-1) * 10 + 1
FROM TB_AttachFile
WHERE IDX_FileGuid > 350 -- 350은 이전 페이지의 끝 게시물 번호. (350보다 큰 10개를 얻음.)
ORDER BY FileGuid DESC
)AS A
)
ORDER BY FileGuid DESC
결과.
게시물은 100만개를 넣고 테스트를 했습니다
서버정보 : CPU : p4-1.8, RAM : 768Mb, 컴팩 프리자리오 2820AP, 환경 : 윈도우2003 MSSQL2000
처음페이지(1), 마지막 페이지(50000) 처리 시간이 아래와 같습니다.(단위 ms)
첫페이지 실행 끝페이지 실행
1 : 273 11476.56
2 : 289 4406.25
3 : 289 2695.31
4 : 289 1218.75
5 : 7.81 23.44
index 체크 유무 (0) | 2009.06.08 |
---|---|
조직도 나타내기 - 재귀적호출 (0) | 2009.05.26 |
여러 로우의 값을 하나의 컬럼으로 바꾸는 방법 (0) | 2009.05.20 |
프로시저에서 중첩된 프로시저 실행 후 트랜잭션 처리될 때 (0) | 2009.05.19 |
LDF 파일 용량 축소 (0) | 2009.05.17 |