새로운 ASP.NET Core 2 프레임 워크가 출시되면서 Microsoft와 그community 에서 MVC (Model-View-Controller) 접근 방식에 대한 새로운 대안을 제공했습니다.Microsoft는 Razor Pages라고 이름을 지었습니다. 조금 다른 접근 방식이지만 Razor Pages는 몇가지 면에서 MVC와 여전히 유사합니다.
이 기사에서는 ASP.NET Razor Pages의 중요한 점을 다룰 것입니다.
Razor Page - 정확히 무엇입니까?
ASP.NET MVC 사용시 단점
Razor Page 사용의 이점
이 두 가지 방법으로 Request 을 처리하는 방법을 비교해보자.
Razor Page - 정확히 무엇입니까?
Razor Page 는 ASP.NET MVC의 View 의 component 와 매우 유사합니다.기본적으로 MVC와 동일한 문법과 기능을 가집니다.
Razor Page 와 MVC의 주요 차이점은 Razor Page 자체 내에Model(모델)과 Controller(컨트롤러) 코드가 포함되어 있다는 것입니다. 간단히 말해 MVVM (Model-View-View-Model) 프레임 워크와 비슷합니다.이는 양방향 데이터 바인딩과 isolated concerns 포함하여 쉬운 개발 경험을 제공합니다.
MVC는 많은 양의 동적 서버 View 들, Single Page App, REST API 및 AJAX 호출이 있는 웹 응용 프로그램에서 잘 작동하지만, Razor Pages는 read-only(읽기 전용) 이거나 기본 데이터 입력을 수행하는 단순한 페이지에 적합합니다.
이제 ASP.NET MVC는 웹 응용 프로그램 개발에서 매우 인기가 있었으며 이는 확실히 장점이 있습니다.실제로 ASP.NET WebForms는 MVC의 MVVM 솔루션으로 특별히 설계되었습니다.
그러나 이 새로운 ASP.NET Core Razor Pages는 차세대 버전의 ASP.NET WebForms 이라고 보시면 됩니다.
ASP.NET MVC 단점
대부분의 사람들이 알고 있는 것처럼, MVC는 Model-View-Controller의 약자입니다.UI (사용자 인터페이스)를 구현하기위한 소프트웨어 개발에 사용되는 아키텍처 패턴입니다.
MVC는 가장 널리 사용되는 프레임 워크 중 하나이며, 전세계 수백만 웹 개발자가 사용하고 있지만 여전히 단점은 존재합니다. 그중에서 중요한 2 가지를 살펴 보겠습니다.
# 1 - 복잡성
ASP.NET MVC에는 TempData, RouteCollection, ViewData, Linq to SQL, Controller Action, Lambda Expression, Custom Route 및 HTML Helpers와 같은 개념들이 많이 있습니다.이 모든 것은 Model, View 및 Controller를 연결합니다.
이런 모든 기본 개념을 배우기 전까지는 ASP.NET MVC를 사용하여 웹 응용 프로그램을 만들 수 없습니다.비록 그것들을 배웠다 하더라도, 여전히 대규모 어플리케이션을 구축 할 때는, 때때로 복잡한 문제에 직면하게 될 것입니다.
# 2 - 잦은 업데이트 비용
ASP.NET MVC에서 웹 개발자는Model 과 View 가 분리되어 있어도 이를 완전히 무시할 수 없습니다.이유는 Model를 자주 변경하면 View 에게 변경에 대한 요청이 넘칠 수 있기 때문입니다.
View 는 기본적으로 그래픽 디스플레이로, 응용 프로그램의 복잡성에 따라 렌더링하는 데 약간의 시간이 걸립니다.응용 프로그램이 복잡하고 모델이 많이 변경된 경우 View 가 업데이트 요청보다 뒤쳐 질 수 있습니다.따라서 개발자는 이런 상황을 변경 및 수정하는데 더 많은 시간을 투자해야 하므로 비용이 높아집니다.
Razor Page 사용의 이점
약 10 년 동안 ASP.NET MVC 개발 서비스를 제공해 왔습니다.사실 Microsoft Gold Partner 인증을 받았습니다.따라서 지식, 경험 및 전문 지식을 토대로, MVC 대신 ASP.NET Core Razor Page를 사용하면 좋은 두 가지 주요 이점을 말씀 드리겠습니다.
# 1 - Razor Page 의 구성이 개선되었습니다.
어떤 종류의 웹 개발에 MVC를 사용한 적이 있다면 전체 앱을 코딩하는 데 걸리는 시간을 알고 있을 것입니다.동적 경로를 만들고, 올바르게 이름을 짓고, 수백 가지의 물건을 만드는 것에 많은 시간을 소비합니다.
한편,Razor Page 는 MVC에 비해 체계적입니다.
Razor Page 에서 파일은 기본적으로 보다 체계적으로 구성됩니다.이전 ASP.NET WebForm과 같은 방식으로Razor Page 와 전체 코드가 Webform 처럼 Code Behind 뒤에 있습니다. 예를 들어 sample.cshtml 그 아래에 sample.cshtml.cs 가 존재합니다.
# 2 - 단일 Responsibility
이전에 MVC 프레임 워크를 사용 해본 적이 있다면 일반적으로 다양한actions 으로 가득 찬 커다란 Controller 클래스가 있다는 것을 알았을 것입니다.이러한 클래스들은 새로운 것들이 점점 추가됨에 따라 더 커지는 바이러스와 같습니다.
그러나 Razor Pages에서는 각 앱 페이지에 자체 View와 Code로 구성되어 있으며 결과적으로 MVC 보다 덜 복잡합니다.
전반적으로 ASP.NET Core 는 Module 식 웹 프레임 워크입니다.
MVC에서 새 항목을 추가할 때마다 .NET Framework 의 새로운 버전으로 릴리스 해야합니다.
예를 들어, 마이크로 소프트는 MVC 4 에Routing를 발표하고 추후 출시할때 Routing 할 Attribute 을다시 또 다른 새로운 프레임 워크인 MVC 5에 공개했습니다.
반면에 ASP.NET Core 에서는 NuGet 패키지를 사용하여 이 모든 것을 관리합니다. 즉, 새로운 항목이 추가 될 때마다 새로운 .net 프레임 워크 버전에 릴리즈 하지 않으므로, 기존 프레임 워크를 업그레이드 하는 MVC보다 쉽습니다.
또한 .NET Core에서 새로운 NuGet 패키지 버전에 대한 업데이트를 릴리스 할 수 있으며, NuGet 패키지를 업데이트하여 최신 변경 사항으로 반영 할 수 있습니다.
이 두 가지 방법으로 Request 을 처리하는 방법을 비교해 보자.
위의 내용에서 ASP.NET Core Razor Page를 사용하여 웹 응용 프로그램을 작성하는 것이 MVC보다 덜 복잡하다고 설명했습니다.여기서 우리는 행동을 통해 그것을 보여줍니다.
먼저 MVC로 시작합니다. 다음은 MVC가 Request 처리하는 방법에 대한 간단한 개요입니다.
보시다시피 Routing 은 MVC가 Request 를 처리하는데 있어서 결정하는 중요한 열쇠입니다.Routing 의 기본 구성은 Action 과 Controller 의 이름으로 조합되어 있습니다.
따라서 /staff/index를 요청하면 StaffController 클래스에서 Index라는 Action 을 Routing 합니다.
그러나 Code 의 Block 이 있는 모든 컨트롤러에 Request 을 Routing 하도록 커스텀마이징 하거나 설정 할 수 있습니다.
Razor Page 와 동일한 비교
Razor Pages가 Request 을 처리하는 방법에 대한 간략한 개요는 다음과 같습니다.
두가지 차이점은 Razor Page 에서 Request 를 하면 기본 Routing 환경의 Page 폴더에서 특정 Request 에 대한 Razor Page 를 찾습니다.
/contact/ 에 대한 Request 를 한다고 가정하면 ASP.NET Core 는 Request 시 사용한 것과 같은 이름을 가진 페이지를 찾아 직접 연결합니다.
즉, /contact/ 에 대한 요청은 Contact.cshtml로 연결됩니다.
그리고 .cshtml 파일을 Razor Page 로 간주하려면 Page Folder 안에 배치해야 하며, 마크 업에 @Page 를 포함해야 합니다.
이렇게 하면 Razor Page 가 Controller 의 동작으로 작동 합니다.이제 MVC와 비교해 보면, 이는 별도의 코딩이 필요 없이 맞춤 경로 구성으로 인해 덜 복잡합니다.
결론적으로
Razor Pages는 2018 년에 "less complexity" 시작으로, 모던웹 앱 개발의 출발점으로 보입니다. 비교에 따르면 특정 Request 와 관련된 모든 것들을 한 곳으로 모으는 장점을 제공하는 것으로 나타났습니다. MVC에서 모든 Request 부분을 분산시켜야 합니다. 응용 프로그램은 거대한 퍼즐과 같습니다. 그런 다음 다시 코딩 작업을 해야 합니다.
SMS 와 Google OTP는 요청시 유효기간이 있는 일회용 패스워드를 사용하므로 사실 동일한 방식이라고 봐도 무방함
SMS는 추가 개발사항이 많지 않으나, Google OTP는 OTP 발급기능 부터 계정별 Secretkey를 관리해야함.
구조
사용자와 서 버는 S/Key와 동일한 방법으로 OTP를 위한 초기화 를 수행한다. 하지만, 사용자는 R값을 저장 또는 기 억할 필요가 없다. 사용자가 인증을 시도할 경우, 서 버는 R값과 반복수를 사용자의 휴대폰으로 SMS를 이용하여 보내게 된다. 사용자는 휴대폰에 자신만이 알고 있는 패스워드를 입력하여, 일회용 패스워드 (OTP)를 만들게 된다. 그러면 사용자는 그 OTP를 PC에 입력하고, 그 값은 서버로 전달되다. 서버는 수신한 OTP검증을 통해서 사용자를 인증하게 된다.
인증 프로토콜
1) 클라이언트는 PC에 ID를 넣는다.
2) PC에서 서버로 먼저 ID가 전달된다.
3) 서버에서는 ID에 대응되는 값과 반복수값을 사용자의 휴대폰에 SMS로 보내준다.
4) 사용자는 자신의 휴대폰에 날아온 SMS를 확인 하고, 자신의 휴대폰에 자신의 패스워드를 입력 한다.
5) 휴대폰에서 OTP를 계산한다.
6) 사용자는 휴대폰에서 계산된 OTP를 PC에 입력 한다.
7) 입력된 OTP는 서버에 전송된다.
서버는 수신한 OTP에 대한 검증을 S/Key와 동일한 방법으로 수행한다. 일회용패스워드에서는 반복수가 제한적이기 때문 에 초기에 설정한 반복수 만큼의 로그인 시도를 했 을 경우에 다시 일회용 패스워드에 관련된 정보를 초기화 해야만 한다.
SharePoint 2013에서 JavaScript Injection을 사용하면 SharePoint 페이지의 DOM에 동적으로 JavaScript를 삽입하여 사용자 지정 기능을 추가할 수 있습니다. 이를 통해 SharePoint 페이지의 모양과 동작을 사용자 지정할 수 있으며, 새로운 사용자 지정 기능을 추가할 수 있습니다.
다음은 SharePoint 2013에서 JavaScript Injection을 사용하는 방법입니다.
SharePoint 2013 페이지에 로그인합니다.
SharePoint 2013 페이지에서 사용자 지정 JavaScript 파일을 만듭니다. 이 파일은 SharePoint 페이지의 DOM에 삽입됩니다.
SharePoint 2013 페이지의 편집 모드로 전환합니다.
SharePoint 2013 페이지에서 삽입할 JavaScript 코드를 선택합니다.
페이지 상단의 "삽입" 메뉴를 선택합니다.
"웹 파트" 영역을 선택합니다.
"문서 라이브러리" 옵션을 선택합니다.
"Script Editor" 옵션을 선택합니다.
"Edit Snippet"을 클릭하여 JavaScript 코드를 입력합니다.
코드를 입력한 후 "적용" 버튼을 클릭합니다.
페이지를 저장하고 SharePoint 2013 페이지에서 새로고침합니다.
이제 SharePoint 2013 페이지에 사용자 지정 JavaScript가 삽입되었습니다. 이제 사용자 지정 JavaScript를 사용하여 SharePoint 페이지의 모양과 동작을 변경할 수 있습니다.
다음은 SharePoint 2013에서 JavaScript Injection을 사용하는 예제 코드입니다.
// JavaScript Injection 예제 코드
// SharePoint 페이지가 완전히 로드될 때까지 기다립니다.
$(document).ready(function () {
// SharePoint 페이지의 "내용" 영역에 사용자 지정 텍스트를 삽입합니다.
$('#s4-bodyContainer').append('<p>이 텍스트는 JavaScript Injection을 사용하여 삽입되었습니다.</p>');
// SharePoint 페이지의 헤더에 사용자 지정 CSS를 적용합니다.
$('head').append('<style>h1 { color: red; }</style>');
// SharePoint 페이지의 "공지사항" 목록을 가져와서 새로운 열을 추가합니다.
var list = $('table.ms-listviewtable');
list.find('thead tr').append('<th>새로운 열</th>');
list.find('tbody tr').each(function () {
$(this).append('<td>새로운 셀</td>');
});
});
위의 코드는 jQuery 라이브러리를 사용하여 SharePoint 페이지의 DOM에 동적으로 요소를 추가합니다. 페이지가 로드된 후 $(document).ready() 함수가 호출되므로 페이지의 요소들이 DOM에 모두 로드된 후 JavaScript 코드가 실행됩니다. 이 코드에서는 SharePoint 페이지의 "내용" 영역에 새로운 텍스트를 추가하고, 페이지의 헤더에 새로운 CSS 스타일을 적용하며, 페이지의 "공지사항" 목록에 새로운 열과 셀을 추가합니다.
참고: 위의 코드는 SharePoint 페이지에서 직접 실행할 수 있는 예제 코드입니다. 그러나 실제로 SharePoint에서 사용자 지정 코드를 작성할 때는 SharePoint의 보안 정책을 고려하여 코드를 작성해야 합니다. 예를 들어, 사용자 입력 데이터의 유효성 검사 및 인증/권한 검사 등 보안 요구 사항을 충족해야 합니다.
ASP.NET에서 CORS(Cross-Origin Resource Sharing) 정책을 허용하려면, 다음과 같은 단계를 따르면 됩니다.
Web API 프로젝트에 Microsoft.AspNet.WebApi.Cors 패키지를 설치합니다.
WebApiConfig.cs 파일을 열고, 다음과 같이 CORS 정책을 설정합니다.
using System.Web.Http;
using System.Web.Http.Cors;
namespace YourWebApiProject
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// CORS 정책 설정
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
// Web API 설정
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
위 코드에서, EnableCorsAttribute 클래스의 인스턴스를 생성하여 CORS 정책을 설정합니다. 이 클래스의 생성자에는 3개의 매개변수가 필요합니다.
origins : 허용할 도메인을 지정합니다. 여기에서는 모든 도메인을 허용하기 위해 "*"를 사용하였습니다.
headers : 요청 헤더에서 허용할 필드를 지정합니다. 모든 헤더를 허용하기 위해 "*"를 사용하였습니다.
methods : 허용할 HTTP 메서드를 지정합니다. 모든 HTTP 메서드를 허용하기 위해 "*"를 사용하였습니다.
ASP.NET Core에서 CORS(Cross-Origin Resource Sharing) 정책을 허용하려면, 다음과 같은 단계를 따르면 됩니다.
Microsoft.AspNetCore.Cors 패키지를 프로젝트에 추가합니다. NuGet을 통해 패키지를 설치할 수 있습니다.
Startup.cs 파일을 열고, ConfigureServices 메서드 내에 다음과 같이 CORS 서비스를 추가합니다.
using Microsoft.Extensions.DependencyInjection;
public void ConfigureServices(IServiceCollection services)
{
// CORS 정책 설정
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
// ...
}
위 코드에서, AddCors 메서드를 사용하여 CORS 서비스를 추가합니다. options.AddPolicy 메서드를 호출하여 "CorsPolicy"라는 이름의 CORS 정책을 설정합니다. 이 정책에서는 모든 도메인, 모든 HTTP 메서드, 모든 요청 헤더를 허용하도록 설정하였습니다.
3. Configure 메서드 내에 다음과 같이 CORS 미들웨어를 추가합니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
// CORS 미들웨어 추가
app.UseCors("CorsPolicy");
// ...
}
위 코드에서, UseCors 메서드를 사용하여 "CorsPolicy"라는 이름의 CORS 정책을 적용합니다. 이제 API 엔드포인트에서 CORS 정책을 적용할 수 있습니다.
참고로 .NET Core에서는, Web.config 파일이 없으므로 httpProtocol 요소를 추가할 필요가 없습니다. 위 코드에서 추가한 CORS 미들웨어를 사용하여, 모든 요청에 대해 CORS 헤더를 추가합니다.
.NET Core 6에서는 추가로 다음과 같은 방법으로도 CORS를 설정할 수 있습니다.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.WithOrigins("http://example.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
var app = builder.Build();
app.UseCors(); // CORS 미들웨어 추가
app.MapGet("/", () => "Hello World!");
app.Run();
위 코드에서, AddDefaultPolicy 메서드를 사용하여 특정 도메인(http://example.com)에 대해 허용할 HTTP 메서드와 요청 헤더를 설정할 수 있습니다. UseCors 메서드를 사용하여 CORS 미들웨어를 추가하고, CORS 정책을 적용할 API 엔드포인트를 지정합니다.
.NET Core 6에서는, ConfigureServices 메서드에서 AddCors 메서드를 사용하지 않아도 기본적인 CORS 지원이 가능합니다. 하지만, 기존 버전과 마찬가지로 AddCors 메서드를 사용하여 더 세부적인 CORS 정책을 설정할 수 있습니다.
ABAP에서 내부 테이블(Internal Table)은 데이터를 저장하고 관리하는 가장 일반적인 방법 중 하나입니다.
내부 테이블은 일반적으로 ABAP 프로그램에서 사용되는 데이터를 저장하기 위해 메모리에 할당됩니다.
내부 테이블은 데이터를 행과 열의 형태로 저장하며, 데이터베이스와 유사한 방식으로 작동합니다.
내부 테이블에는 필드 이름과 필드 유형이 정의됩니다. 내부 테이블을 사용하여 데이터를 처리할 때, 데이터에 대한 빠른 액세스와 처리가 가능합니다. 내부 테이블을 정의하는 방법은 다음과 같습니다.
DATA <table_name> TYPE STANDARD TABLE OF <data_type> WITH NON-UNIQUE KEY <key_field>.
여기서 <table_name>은 내부 테이블의 이름, <data_type>은 테이블의 데이터 유형, <key_field>는 내부 테이블에서 고유한 키를 생성하는 필드 이름입니다.
내부 테이블을 사용하여 데이터를 삽입, 수정, 삭제, 검색 및 정렬할 수 있습니다. 내부 테이블을 사용하는 예시는 다음과 같습니다.
DATA: BEGIN OF itab OCCURS 0,
col1 TYPE string,
col2 TYPE i,
END OF itab.
itab-col1 = 'ABAP'.
itab-col2 = 123.
APPEND itab.
위의 코드에서는 itab이라는 내부 테이블을 정의하고, col1과 col2라는 두 개의 필드를 포함하고 있습니다. 그 다음, itab의 레코드를 생성하고, 데이터를 삽입한 후, APPEND 함수를 사용하여 itab에 추가합니다. 이렇게 하면 itab 내부 테이블에 데이터가 추가됩니다.
내부 테이블은 많은 경우 ABAP 프로그램에서 데이터를 처리하기 위한 가장 적합한 방법 중 하나입니다.
PowerShell에서 try-catch 구문을 사용하여 예외 처리를 구현하는 방법은 다음과 같습니다.
try {
# 예외 발생 가능성이 있는 코드 블록
}
catch {
# 예외 처리 코드 블록
}
위의 구문에서, try 블록 안에는 예외가 발생할 수 있는 코드가 들어갑니다. catch 블록은 예외가 발생했을 때 실행되는 블록으로, 예외 처리에 사용됩니다.
예를 들어, 다음과 같은 코드에서는 파일을 열고 내용을 읽는데 실패할 경우 예외가 발생합니다.
try {
$file = Get-Content "C:\example.txt"
}
catch {
Write-Host "파일을 열 수 없습니다: $_. Exception Type: $($_.Exception.GetType().FullName)"
}
try 블록 안에 Get-Content 명령어로 파일을 읽고, catch 블록에서는 예외 처리를 담당합니다. 여기서 $_는 현재 발생한 예외를 나타내며, Exception.GetType().FullName은 예외의 타입을 나타냅니다. 이렇게 하면 어떤 종류의 예외가 발생했는지 확인할 수 있습니다.
try-catch 구문을 사용하여 예외 처리를 구현할 때, 어떤 예외가 발생할 수 있는지 미리 파악하고 예외에 대한 처리 방법을 정하는 것이 중요합니다.
이 예시에서는 로깅 수준, 호스트 접근 제한, 데이터베이스 연결 문자열 등의 설정값이 정의되어 있습니다.
또한, IConfiguration 인터페이스를 사용하여 appsettings.json 파일에 정의된 설정값을 읽어올 수 있습니다. 이를 위해서는 다음과 같은 코드를 사용합니다:
using Microsoft.Extensions.Configuration;
public class MyClass
{
private readonly IConfiguration _config;
public MyClass(IConfiguration config)
{
_config = config;
}
public void MyMethod()
{
var connectionString = _config.GetConnectionString("DefaultConnection");
// ConnectionString 값 사용
}
}
이렇게 IConfiguration 인터페이스를 사용하여 appsettings.json 파일에 정의된 설정값을 읽어오면, API 서버에서 설정값을 관리할 수 있습니다.
ASP.NET Core는 작업 메서드 매개 변수에서 [Required] 또는 [BindRequired] 특성을 사용하여 도움을 줄 수 있습니다.
[ApiController]
[Route("[controller]")]
public class ProductController : ControllerBase
{
[HttpGet]
public IActionResult Get([Required] int id) => Ok();
}
[ApiController]
[Route("[controller]")]
public class ProductController : ControllerBase
{
[HttpGet]
public IActionResult Get([BindRequired] int id) => Ok();
}
두 컨트롤러 모두 id 매개변수 없이 호출될 때 유효성 검사 오류를 반환합니다.
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|7fb5e16a-4c8f23bbfc974667.",
"errors":{
"Id":[
"A value for the 'Id' parameter or property was not provided."
]
}
}
하나의 필드 인덱스를 사용하는 것을 단일 필드 인덱스라고 합니다. MongoDB에는 기본적으로 컬렉션에 _id라는 단일 필드 인덱스가 생성됩니다.
단일 필드 추가 방법은 아래와 같습니다. 원하는 feild를 입력합니다.단일 필드 인덱스에서는 1은 오름차순 -1은 내림차순을 의미합니다. 하지만 단일 필드 인덱스에서는 오름차순인지 내림차순인지 중요하지 않습니다.왜냐하면 어떤 방향으로 가도 동일하게 접근하기 때문입니다.
> db.user.createIndex({score:1})
아래 그림은 score에 인덱스를 주어 score 크기대로 오름차순(숫자 1이 오름차순, 숫자 -1은 내림차순입니다.) 정렬된 것을 확인할 수 있습니다.
아래와 같이 인덱스를 생성한다면, 아래 그림과 같이 userid는 오름차순으로 정렬됩니다. 그리고 같은 userid를 지니면 score로 내림차순 정렬하게 됩니다. 예를 들면 동일한 userid 인"ca2"는 score가 내림차순으로 정렬되어 있음을 그림에서 확인할 수 있습니다.
복합 인덱스를 사용할 때는 아래의 특징을 고려하며 생성합시다. 이는MongoDB 문서에서 확인할 수 있습니다.
- 특징 1. sort 연산 시 인덱스 순서를 고려하여 생성하자.
복합 인덱스에서는 키의 순서가 매우 중요합니다. 만일 복합 인덱스에서 순서가 userid-score가 아니라 score-userid로 생성하는 것은 다른 인덱스를 생성한 것입니다.
정렬 시 인덱스 순서와 조회 시 순서가 동일해야 합니다. 예를 들어 아래와 같이 인덱스 a-b순서로 생성하면 a-b 정렬은 지원을 하지만, b-a로 정렬은 지원하지 않습니다.
- 특징 2. 단일 인덱스와 다르게 복합 인덱스는 정렬 방향을 고려하자.
검색 쿼리에서 복합 인덱스를 사용하는 경우 지정된 정렬 방향은 index와 일치해야 합니다. 예를 들어 아래와 같이 두 필드 정렬이 역으로 생성된 경우라면 역으로 조회하는 쿼리는 지원하지만, 동일한 정렬을 하는 쿼리는 지원하지 않습니다.
- 생성된 인덱스: { a: 1, b: -1 }
- 지원하는 조회 쿼리: { a: 1, b: -1 }
- 지원하는 조회 쿼리: { a: -1, b: 1 }
- 지원하지 않는 조회 쿼리: { b: 1, a: 1 }
- 지원하지 않는 조회 쿼리: { b: -1, a: -1 }
아래 예제로 실습을 진행해 봅시다. 이전에 생성한 인덱스는 drop 하고 진행해 봅니다. {userid:1, score:-1} 인덱스를 생성합니다. 순서를 동일 시한 실행은 문제없이 실행됩니다. 반면 정렬 순서를 역으로 하지 않거나 순서를 다르게 한 경우는 정상 동작하지 않습니다.
> db.user.createIndex({userid:1, score:-1})
# 실행 시 문제 없이 진행
> db.user.find({}).sort({ userid:1,score:-1})
> db.user.find({}).sort({ userid:-1,score:1})
# RAM exceeded error 발생
> db.user.find({}).sort({ userid:1,score:1})
> db.user.find({}).sort({ score:-1,userid:1})
- 특징 3. Prefixes
Index prefixes란 조회 시 왼쪽 인덱스부터 적용되는 부분집합 인덱스를 말합니다. 정의가 이해하기 어려우니 아래의 예시로 이해해 봅시다. a, b, c, d 복합 인덱스를 생성할 때 { a: 1 }~{ a:1, b: 1, c: 1, d: 1 }까지 적용됩니다. 따라서 이런 인덱스를 생성할 시 {a:1} 인덱스가 정의되어 있다면, 삭제해도 상관없습니다. 왜냐면 { a:1, b: 1, c: 1, d: 1 } 인덱스로 인해 조회가 빠르게 이뤄질 것입니다.
- 생성된 인덱스: { a:1, b: 1, c: 1, d: 1 }
아래 예시로 어떤 index prefixes 가 적용되는지 확인해 봅니다.
- 생성된 인덱스: { "item": 1, "location": 1, "stock": 1 }
- 지원되는 쿼리: { item: 1 }
- 지원되는 쿼리: { item: 1, location: 1 }
- 지원하지 않는 조회 쿼리: "item" 필드 없이 "location" 필드만 존재 혹은 "stock" 필드만 존재
- 지원하지 않는 조회 쿼리: "item" 필드 없이 "location", "stock" 필드만 존재
- 특징 4. sort 연산은 non-prefix를 지원한다.
sort 연산은 특징 3에서 배운 prefix 조건에 맞지 않아도 지원을 합니다. 그러나 이를 만족하기 위해서는 쿼리는 equality 조건은 prefix를 포함해야 합니다. 아래 예제로 이를 이해해 봅시다.
- 생성된 인덱스: { a:1, b: 1, c: 1, d: 1 }
아래 표 예제는 위에 생성된 인덱스에 만족하는 쿼리입니다. 앞에 equality 조건은 모두 prefix를 만족합니다. 그러나 sort 부분은 prfix 조건을 만족하지 않지만 올바르게 사용된 쿼리 입니다.
아래 실습은 쿼리에.explain("executionStats").executionStats.executionTimeMillis를 넣어 실행 시간을 파악하였습니다. "userid" 없이 "score" 필드를 조건에 넣은 표 두 번째 쿼리는 실행 시간을 통해 적용이 안 된 것임을 알 수 있습니다. 또한, 6번째 쿼리도 prefix를 지키지 않아 적용이 안 됨을 알 수 있습니다.