Spring Bean Container


스프링 빈 컨테이너 역할

스프링 객체를 관리한다 : 컨테이너가 스스로 객체를 생성한다

1) @ComponentScan : @Component가 붙은 클래스들을 읽어서 객체로 생성한다

2) @Bean : @Bean을 이용하여 개발자가 생성하는 코드를 작성한다.



@Configuration

-> class 가져올 때 반드시 사용해야함


@Import 

-> configure 파일 가져옴


@Import({DVDConfig.class, DVDPlayerConfig.class})

두가지 클래스 믹싱하는 방법


@Component 종류에는

-> 1. @Controller - @RestController

    2. @Service

    3. @Repository


@RestController : @RestController -> @Controller 안으로 들어가면 @Component 어노테이션이 있다.

@Component 어노테이션이 붙어 있으면 스프링 Bean Container가 모두 객체를 생성한다.(개발자가 직접 new()를 사용하는 것과 같은 역할)


@ComponentScan

-> 루트 패키지 이하의 클래스 중 @Component 어노테이션이 붙은 클래스 검색








https://jhkang-tech.tistory.com/44

mybatis에서 조건문 쓰는 것은 간단하다.

if나 when을 써주면 된다.


if문

1  
2<if test="조건내용">
3수행할 query
4</if>
5  


when문 

01  
02<choose>
03    <when test="조건내용">
04      ....
05    </when>
06    <otherwise>
07      .....
08    </otherwise>
09</choose>
10  


test에 조건내용을 써주면 되는데 연산문은 일반적이다.


==, eq, !=, or, and 뭐 이런식으로 써주면 된다.


그렇다면 반복문은 어떻게 할 것인가?


예를들어 query의 where절에 in을 쓰고 싶다.


회원아이디들을 여러개 조회해와서 그 아이디가 있는 데이터만 가져오고 싶은 것이다.


요런 쿼리가 있다고 치자. 물론 서브쿼리로 간단히 할수 있다


select * from tblEventJoiner where event_no=#{event_no} and userid in (select userid from tblMember where smsyn = 'Y')


그런데 서브쿼리를 썼더니 시간이 너무 많이 걸린다. (물론 저런 간단한 쿼리에서는 걸리지않는다. 조인이 네다섯개 이상 걸린 경우)


프로시져를 짜도 되지만...이게 귀찮다면 다음과 같이 해보자.


1. 우선 SMS수신동의자 회원을 가져온다. (query.xml)

1  
2<select id="getMembersSMS" parameterType="string" resultType="String">
3select userid from tblMember where smsyn = #{SMS_YN}
4</select>
5  


2. DAO부분에서 이 리스트를 받아 다시 query를 조회한다. (eventDAO.java)

01  
02public List<EventVO> getEventJoiner(EventVO vo)throws Exception{
03     //SMS수신한 회원 리스트 가져오기
04    List<String> member_list = list("event.getMembersSMS", "Y");
05  
06    Map<String, Object> map = new HashMap<String, Object>();
07    map.put("vo", vo);
08    map.put("member_list", member_list);
09 
10   //return할 이벤트 참여자리스트
11   List<EventVO> list = null;
12   if(member_list.size() >0){
13       list = list("event.getEventJoiner", map);
14   }
15 
16  return list;
17}
18  


3. 다시 query.xml로 돌아가서 받아온 회원아이디 리스트로 where절에 in을 넣어보자

01  
02<select id="getEventJoiner" parameterType="map" resultType="EventVO">
03 
04select * from tblEventJoiner
05    where event_no=#{vo.event_no}
06   <choose>
07     <when test="member_list.size != 0">
08               and userid in 
09            <foreach collection="member_list" item="item" index="index" separator="," open="(" close=")">
10              #{item}
11            </foreach>
12     </when>
13     <otherwise>
14     and userid  = '-'
15     </otherwise>
16    </choose>
17</select>
18  



출처: https://narei.tistory.com/entry/mybatis에서-foreach문-쓰기 [Run!]

1. 삭제하시겠습니까? 팝업창 필요 [삭제 실패하였습니다.][삭제 완료하였습니다.]



1. 

1. 페이징 화면 처리


URL의 파라미터를 이용해서 정상적으로 원하는 페이지로 이동하는 것을 확인 했다면, 화면 밑에 페이지 번호를 표시하고 사용자가 페이지 번호를 클릭할 수 있게 처리합니다.

페이지를 보여주는 작업은


- 브라우저 주소창에서 페이지 번호를 전달해서 결과를 확인하는 단계

- JSP에서 페이지 번호를 출력하는 단계

- 각 페이지 번호에 클릭 이벤트 처리

- 전체 데이터 개수를 반영해서 페이지 번호 조절


페이지 처리는 단순히 링크의 연결이기 때문에 어렵지는 않지만, 다음과 같이 목록페이지에서 조회페이지, 수정,삭제 페이지까지 페이지 번호가 계속 유지되어야만 하기 때문에 끝가지 신경써야 하는 부분이 많은 편이다. 



* 화면 페이지 처리할 때 필요한 정보들

화면에 페이징 처리를 하기 위해서는 우선적으로 여러가지 필요한 정보들이 존재합니다. 화면에 페이지는 크게 다음과 같은 정보들이 필요합니다.

 - 현재 페이지 번호(page)

 - 이전과 다음으로 이동 가능한 링크의 표시 여부(prev,next)

 - 화면에서 보여지는 페이지의 시작 번호와 끝 번호(startPage,endPage)


2. 검색 처리


게시물 관리에서 마지막은 다양한 검색 처리입니다. 검색 기능은 다시 검색 조건과 키워드로 나누어 생각해 볼 수 있습니다. 검색 조건은 일반적으로 <select> 태그를 이용해서 작성하거나 <checkbox>를 이용하는 경우가 많습니다. 과거에는 <checkbox>를 이용하는 경우가 더 많았지만, 최근에는 일반 웹 사이트에서 일반 사용자들의 경우에는 <select>를 관리자용이나 검색 기능이 강한 경우<checkbox>를 이용하는 형태가 대부분입니다.


예제에서는 가장 흔한<select> 태그를 이용해서 검색 기능과 화면을 처리한다.


* 검색 기능과 SQL

게시물의 검색 기능은 다음과 같이 분류가 가능하다.

-제목/내용/작성자와 같이 단일 항목 검색

-제목 or 내용, 제목 or 작성자, 내용 or 작성자, 제목 or 내용 or 작성자와 같은 다중 항목 검색


검색 항목은 제목/내용/작성자와 같은 단일 항목 검색과 제목 or 내용과 같이 복합적인 항목으로 검색하는 방식이 존재합니다.

게시물의 검색이 붙으면 가장 신경쓰이는 부분은 역시 SQL쪽입니다. 오라클은 페이징 처리에 인라인뷰를 사용하기 때문에 실제로 검색 조건에 대한 처리는 인라인뷰 내부에서 이루어져야 합니다. 단일 항목의 검색은 검색 조건에 따라서 칼럼이 달라지고, LIKE 처리를 통해서 키워드를 사용하게 됩니다. 만일 2 페이지에 해당하는 데이터를 '제목'으로 검색하고, 키워드는 'Test'라고 한다면 


검색 조건 제목( title),내용 (content), 작성자(writer)

SQL


select * from ( select

rownum rn,bno,title,content,writer,regdate,updatedate 

from tbl_board

where

---변경부분

title like %Test%

and rownum <=20

)

where rn > 10;


단일 항목은 인라인뷰 안쪽에서 필요한 데이터를 가져올 대 검색 조건이 적용되어야 하기 때문에 WHERE문 뒤에 검색 조건이 추가되고, ROWNUM 조건이 뒤따르게 하면 문제가 없습니다.


**AND 와 OR가 섞여 있는 SQL을 작성할 때에는 우선 순위 연산자인'()'를 이용해서 OR 조건들을 처리해야 합니다. 안그러면 AND연산자가 OR연산자보다 우선순위가 높기때문에 AND먼저 수행됨.


검색 조건 제목 or 내용/ 제목 or 작성자 / 제목 or 내용,작성자

--정상적으로 처리하기 위해서는 ( )를 이용해서 OR 조건을 처리해야만 한다.

select * from

( select 

row rn,bno,title,content,writer,regdate,updatedate

from tbl_board

where 

(title like '%Test%' or content like '%Test%')

and rownum <= 20

)

where rn > 10;



결과를 보면 10개만 출력됨을 알 수 있다.



*MyBatis의 동적 태그들


SQL문에서 느낀 점은 검색 조건이 변하면 SQL의 내용 역시 변하기 때문에 XML이나 어노테이션 같이 고정된 문자열을 작성하는 방식으로는 제대로 처리할 수 없다는 사실입니다.

다행히 MyBatis는 동적(Dynamic) 태그 기능을 통해서 SQL파라미터들의 조건에 맞게 조정할 수 있는 기능을 제공합니다. MyBatis의 동적 태그는 약간의 구문을 이용해서 전달되는 파라미터를 가공해서 경우에 따라 다른 SQL을 만들어서 실행 할 수 있습니다.


예시

if

choose(when, otherwise)

trim(where, set)

foreach



3. 댓글 처리 RestAPI 와 Ajax를 활용하는 댓글 처리

MyBatis는 SQL을 그대로 사용할 수 있기 때문에 인라인뷰를 이용하는 SQL을 작성하고, 필요한 파라미터를 지정하는 방식으로 페이징 처리를 하게 됩니다.


여기서 신경 써야 하는 점은 페이징 처리를 위해서는 SQL을 실행 할 때 몇 가지 파라미터가 필요하다는 점입니다. 페이징 처리를 위해서 필요한 파라미터는 

1) 페이지 번호(pageNum), 2) 한 페이지당 몇 개의 데이터(amount)를 보여줄 것인지가 결정되어야만 합니다.


페이지 번호와 몇 개의 데이터가 필요한지를 별도의 파라미터로 전달하는 방식도 나쁘지 않지만, 아예 이 데이터들을 하나의 객체로 묶어서 전달하는 방식이 나중을 생각하면 좀 더 확장성이 좋습니다.




*Lombok을 이용해서 소스다이어트를 한다.

 롬복은 자바에서 Model(DTO,VO,Domain) Object를 만들 때, 멤버필드(프로퍼티)에 대한 Getter/Setter, ToString과 멤버필드에 주입하는 생성자를 만드는 코드 등 불필요하게 

 반복적으로 만드는 코드를 어노테이션을 통해 줄여 주는 라이브러리, 프로젝트 입니다.

 사실 반복되는 Getter,Setter,toString을 자동으로 해주는것만으로도 좋다. 즉, 어노테이션 가능하게 해주는 좋은 툴



Criteria 클래스의 용도는 '검색의 기준'을 의미합니다. pageNum과 amount 값을 같이 전달하는 용도지만 생성자를 통해서 기본값을 1페이지,10개로 지정해서 처리합니다. lombok을 이용해서 getter/setter를 만든다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package org.zerock.domain;
 
//Criteria == '검색 기준,분류 기준'
public class Criteria {    
    private int page;
    private int perPageNum;
    
    public Criteria() {
        System.out.println("Criteria생성");
        this.page = 1;
        this.perPageNum = 10;
    }
    
    public void setPage(int page) {
        System.out.println("Cri.setPage호출");
        if(page <= 0) {
            this.page = 1;
            return;
        }        
        this.page = page;
    }
    
    public void setPerPageNum(int perPageNum) {
        System.out.println("Cri.setPerPageNum호출");
        if (perPageNum <= 0 || perPageNum > 100) {
            this.perPageNum = 10;
            return;
        }
        
        this.perPageNum = perPageNum;        
    }
    
    public int getPage() {
        return page;
    }
    
    //method for MyBatis SQL Mapper
    public int getPageStart() {
        return (this.page - 1* perPageNum;
    }
    
    //method for MyBatis SQL Mapper
    public int getPerPageNum() {
        return perPageNum;
    }
    
    @Override
    public String toString() {
        return "Criteria [page="+page+", perPageNum:"+perPageNum+"]";
    }
}
 
cs



MyBatis 처리와 테스트


BoardMapper는 인터페이스와 어노테이션을 이용하기 때문에 페이징 처리와 같이 경우에 따라 SQL구문 처리가 필요한 상황에서는 복잡하게 작성됩니다.(SQL문이 길어지고 복잡해지면 개인적으로는 XML로 처리하는 것이 더 알아보기 쉽고 관리하기도 쉽다고 생각합니다.)


org.zerock.mapper패키지의 BoardMapper에는 위에서 작성한 Criteria 타입을 파라미터로 사용하는 getListWithPaging() 메서드를 작성합니다.



BoardMapper클래스와 


BoardMapper.xml 파일을 수정한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.zerock.mapper.BoardMapper">
    <select id="listSearch" resultType="BoardVO">
    <![CDATA[
    select
        bno,title,content,writer,regdate,viewcnt
    from
        tbl_board
    where bno>0        
    ]]>    
        <include refid="search"></include>
    <![CDATA[
        order by bno desc,regdate desc
        limit #{pageStart},#{perPageNum}    
    ]]>    
    </select>        
    <select id="listSearchCount" resultType="int">
    <![CDATA[
    select
        count(bno)
    from
        tbl_board
    where
        bno > 0
    ]]><include refid="search"></include>        
    </select>
 
    <update id="update">
    update 
        tbl_board 
    set 
        title= #{title}, content= #{content}
    where bno= #{bno}    
    </update>
    
    
    <select id="read" resultType="BoardVO">
    select
        bno,title,content,writer,regdate,viewcnt
    from 
        tbl_board
    where bno= #{bno}
    </select>    
 
    <delete id="delete">
    delete from tbl_board where bno= #{bno}
    </delete>
        
    <insert id="create">
    insert into tbl_board(title,content,writer)
    values(#{title},#{content},#{writer})    
    </insert>
    
    <select id="listAll" resultType="BoardVO">
    <![CDATA[
    select
        bno,title,content,writer,regdate,viewcnt
    from
        tbl_board
    where bno >0
    order by bno desc,regdate desc
    ]]>    
    </select>
    
    <select id="listPage" resultType="BoardVO">
    <![CDATA[
    select
        bno,title,content,writer,regdate,viewcnt
    from
        tbl_board
    where bno>0
    order by bno desc,regdate desc
    limit #{pageStart},#{perPageNum}        
    ]]>
    </select>
    
    <select id="countPaging" resultType="int">
    <![CDATA[
    select
        count(bno)
    from
        tbl_board
    where
        bno > 0
    ]]>
    </select>
    
    
    
    <sql id="search">
    <if test="searchType != null">
        <if test="searchType=='t'.toString()">
            and title like CONCAT('%',#{keyword},'%')
        </if>
        
        <if test="searchType=='c'.toString()">
            and content like CONCAT('%',#{keyword},'%')
        </if>
        
        <if test="searchType=='w'.toString()">
            and writer like CONCAT('%',#{keyword},'%')
        </if>
        
        <if test="searchType=='tc'.toString()">
            and (title like CONCAT('%',#{keyword},'%') OR content like CONCAT('%',#{keyword},'%'))
        </if>
        
        <if test="searchType=='cw'.toString()">
            and (content like CONCAT('%',#{keyword},'%') OR writer like CONCAT('%',#{keyword},'%'))
        </if>
        
        <if test="searchType=='tcw'.toString()">
            and (title like CONCAT('%',#{keyword},'%') OR 
                content like CONCAT('%',#{keyword},'%') OR 
                writer like CONCAT('%',#{keyword},'%'))
        </if>
    </if>    
    </sql>    
    
 
</mapper>
 
cs

이게 지금 오라클 데이터베이스 문법이라서 약간 헷 갈리기도 하다.


1. 프로젝트 생성 후 pom.xml의 수정 ->  데이터베이스 관련 처리 -> 스프링 MVC 처리와 같은 처리



2. 시퀀스를 생성할 때는 데이터베이스의 다른 오브젝트를 구분하기 위해서 'seq_'와 같이 시작하는 것이 일반적입니다. 

 테이블을 생성할 때는 'tbl_' 로 시작 하거나 't_'와 같이 구분이 가능한 단어를 앞에 붙여주는 것이 좋습니다.

 tbl_board 테이블은 고유의 번호를 가지기 위해서 bno 칼럼을 지정했고, 제목(title),내용(content), 작성자(writer)를 칼럼으로 지정합니다.

 테이블을 설계할 때는 가능하면 레코드의 생성 시간과 최종 수정 시간을 같이 기록하는 것이 좋기 때문에 생성 시간(regdate)과 레코드의 최종 수정 시간(updatedate)칼럼을 작성   합니다. 이때 기본 값으로 sysdate를 지정해서 레코드가 생성된 시간은 자동으로 기록될 수 있게 합니다.


테이블 생성 이후에는 'alter table..'을 이용해서 테이블에 Primary Key(이하 PK)를 지정해 주었습니다. PK를 지정할때 'pk_board'라는 이름을 부여하는데, 이 이름은 뒤에서 중요하게 사용되므로 반드시 의미를 구분할 수 있게 생성해 주는 것이 좋습니다.


테이블을 생성하고 나면 여러개의 데이터를 추가해주는데 이런 의미없는 데이터를 더미 데이터라고 합니다. 

insert into tbl_board(bno,title,content,writer)

values(seq_board.nextval, '테스트 제목', '테스트 내용', 'user00');


3. 실행계획과 order by 그 상위단 내용은 오라클 데이터베이스의 페이징 처리(여기가 왜 페이징 처리인지 물어보기)


오라클의 페이징 처리를 제대로 이해하기 위해서 반드시 알아두어야 하는 것이 실행 계획 입니다.(execution plan)입니다. 실행계획은 말 그대로 'SQL을 데이터베이스에서 어떻게 처리할 것인가?'에 대한 것 입니다. SQL이 데이터베이스에 전달되면 데이터베이스는 여러 단계를 거쳐서 해당 SQL을 어떤 순서와 방식으로 처리할 것인지 계획을 세우게 됩니다.


데이터베이스에 전달된 SQL문은 아래와 같은 과정을 거쳐서 처리됩니다. 


SQL파싱 -> SQL최적화 -> SQL실행


SQL파싱 단계에서는 SQL구문에 오류가 있는지 SQL을 실행해야 하는 대상 객체( 테이블, 제약조건, 권한 등) 가 존재하는지를 검사합니다. SQL최적화 단계에서는 SQL이 실행되는데 필요한 비용(cost)를 계산하게 됩니다. 이 계산된 값을 기초로 해서 어떤 방식으로 실행하는 것이 가장 좋다는 것을 판단하는 '실행계획(execution plan)'을 세우게 됩니다.


SQL실행 단계에서는 세워진 실행계획을 통해서 메모리상에서 데이터를 읽거나 물리적인 공간에서 데이터를 로딩하는 등의 작업을 하게 됩니다. 

개발자들은 도구를 이용하거나 SQL Plus등을 이용해서 특정한 SQL에 대한 실행 계획을 알아볼 수 있습니다. SQL Developer에서는 간단히 버튼을 클릭해서 실행 계획을 확인할 수 있습니다.


예를들어, '게시물 번호의 역순으로 출력하라' 는 처리를 한다면 SQL Developer에서 다음과 같이 처리가 가능합니다. 


상단 버튼 중에서 SQL에 대해서 실행 계획을 쉽게 볼 수 있도록 버튼이 제공됩니다.


실행계획을 보면 트리 구조로 방금 전 실행한 SQL이 어떻게 처리된 것인지를 알려줍니다. 흔히 SQL튜닝이라고 하는 작업은 이를 보고 어떤 방식이 더 효과적인지를 판단해서 수정하게 됩니다.


이 책에서는 실행 계획에 대해서 많은 내용을 설명할 수 없지만, 가장 간단하게 실행계획을 보는 방법은 '안쪽에서 바깥쪽으로, 위에서 아래로'봐주면 됩니다. 

위 그림의 내용을 해석하자면 'TBL_BOARD' 테이블을 'FULL'로 접근하고 정렬했다는 것을 의미합니다. 'FULL'이라는 것의 의미는 테이블 내의 모든 데이터를 스캔( scan) 했다는 의미입니다. 실행 계획을 세우는 것은 데이터베이스에서 하는 역할이기 때문에 데이터의 양이나 제약조건 등 여러 상황에 따라서 데이터베이스는 실행계획을 다르게 작성합니다.


테스트를 위해서 데이터가 좀 많아지도록 아래의 SQL을 여러 번 실행해서 데이터를 수백만 개로 만든 후에 커밋을 합니다.


~~~내용이 있고 수백만개의 데이터를 insert 한다는~~~~~


실행계획을 잠깐 살펴 보면 TBL_BOARD를 'FULL'로 조사(스캔)했고, 바깥쪽으로 가면서 'SORT'가 일어난 것을 볼 수 있습니다. 이때 가장 많은 시간을 소모하는 작업은 정렬 작업입니다.


위의 SQL에서 ' order by bno + 1 desc'라는 조건에서 +1 을 하는 것은 정렬에 아무런 도움을 주지 않으므로 아래와 같이 수정합니다.


select * from tbl_board order by bno desc;


기존의 SQL이 TBL_BOARD 테이블 전체를 스캔했지만, 이번에는 PK_BOARD라는 것을 이용해서 접근하고 기존과 달리 맨 위의 SORT과정이 없는 것을 볼 수 있습ㄴㅣ다.


이것을 이해하려면 데이터베이스의 인덱스(index)에 대해서 조금 알아둘 필요가 있습니다.


4. order by  보다는 인덱스


-> 데이터가 많은 상태에서는 정렬 작업이 문제가 됩니다. 이를 어떻게 해결해야 할까요? 가장 일반적인 해결책인 '인덱스(index)를 이용해서 정렬을 생략하는 방법입니다.

결론 부터 말하자면 '인덱스'라는 존재가 이미 정렬된 구조이므로 이를 이용해서 별도로 정렬을 하지 않습니다.


SQL의 실행 계획에서 주의해서 봐야 하는 부분은 1) SORT를 하지 않았다는 점, 2) TBL_BOARD를 바로 접근하는 것이 아니라 PK_BOARD를 이용해서 접근한 점, 3) RANGE SCAN DESCENDING, BY INDEX ROWID로 접근했다는 점입니다.


4.1  PK_BOARD라는 인덱스


tbl_board테이블을 생성했을때의 sql


create table tbl_board(

bno number(10,0),

title varchar2(200) not null,

content varchar2(2000) not null,

writer varchar2(50) not null,

regdate date default sysdate,

updatedate date default sysdate

);


alter table tbl_board add constraint pk_board

primary key(bno);



테이블을 생성할 때 제약조건으로 PK를 지정하고, PK의 이름이 'pk_board'라고 지정하였습니다. 데이터베이스에서 PK는 상당히 중요한 의미를 가지는데

흔히, 식별자의 의미와 인덱스의 의미를 가집니다.



인덱스는 말그대로 색인입니다. 우리가 흔히 접하는 인덱스는 도서 뒤쪽에 정리되어 있는 색인입니다. 색인을 이용하면 사용자들은 책 전체를 살펴볼 필요 없이 색인을 통해서 자신이 원하는 내용이 책의 어디에 있는지 알 수 있습니다. 데이터베이스에서 인덱스를 이해하는 가장 쉬운 방법은 데이터베이스의 테이블을 하나의 책이라고 생각하고 어떻게 데이터를 찾거나 정렬하는지를 생각하는 것입니다. 색인은 사람들이 쉽게 찾아볼 수 있게 알파벳 순서나 한글 순서로 정렬합니다. 이를 통해서 원하는 내용을 위에서 부터 혹은 반대로 찾아나가는데 이를 '스캔(scan)'이라고 합니다.


데이터베이스에 테이블을 만들때 PK를 부여하면 지금까지 얘기한 '인덱스'라는 것이 만들어집니다.

데이터베이스를 만들 떄 PK를 지정하는 이유는 '식별'이라는 의미가 있지만, 구조상으로는 '인덱스'라는 존재(객체)가 만들어지는 것을 의미합니다.

tbl_board 테이블은 bno라는 칼럼을 기준으로 인덱스를 생성하게 됩니다 .인덱스에는 순서가 있기 때문에 그림으로 표현하자면 


인덱스를 역순으로 찾기 때문에 가장 먼저 찾은 bno 값은 가장 큰 값을 가진 데이터가 됩니다. 이후에는 테이블에 접근해서 데이터를 가져오게 되는데, 이런 과정이 반복되면 정렬을 하지 않아도 동일하게 정렬된 결과를 볼 수 있게 됩니다.


하나의 예를 더 보자면, 만일 사용자가 'bno의 순서로 정렬해 달라'고 요구하는 상황이라면 PK_BOARD 인덱스가 앞에서부터 찾아서 내려가는 구조를 이용하는 것이 효율적입니다. SQL Developer를 이용해서 실행해 보면 아래와 같은 실행 계획이 수립되는 것을 볼 수 있습니다.


실행 계획상으로 PK_BOARD 인덱스를 먼저 접근하고, TBL_BOARD를 이용하는 것을 볼 수 있습니다. SORT가 없기 때문에 0초에 가까운 성능을 보여줍니다. 실무에서도 데이터의 양이 많고 정렬이 필요한 상황이라면 우선적으로 생각하는 것이 '인덱스'를 작성하느나 것입니다. 데이터의 양이 수천,수만 개 정도의 정렬은 그다지 부하가 걸리지 않지만 그 이상의 데이터를 처리해야 하는 상황이라면 정렬을 안할 수 있는 방법에 대해서 고민해야만 합니다.


오라클에는 hint가 있지만 mysql에서는 hint라는 문법을 사용하지 않는다.

오라클에서 ROWNUM이라는 특별한 키워드를 사용해서 데이터에 순번을 붙여 사용합니다.

+ Recent posts