반응형

1. Function Scalar Subquery 변경

ㅇ 서브쿼리의 위치에 따른 명칭
    - SELECT문에 있는 서브쿼리 : 스칼라 서브쿼리
    - FROM절에 있는 서브쿼리 : 인라인 뷰
    - WHERE절에 있는 서브쿼리 : 서브쿼리
ㅇ 스칼라 서브쿼리(Scala Subquery)
    - SELECT문에서 사용하는 서브쿼리로 1행만 반환

-- 1. 수정 전
SELECT PRODUCT_CD,
PRODUCT_NAME,
SUM(GET_AVG_STOCK(PRODUCT_CD, :B1, :B2)) AVG_STOCK
FROM PRODUCT
WHERE CATEGORY_CD = ’20’
GROUP BY PRODUCT_CD,
PRODUCT_NAME


-- 2. 수정 후(스칼라 서브쿼리 적용)
SELECT PRODUCT_CD,
PRODUCT_NAME,
SUM((SELECT GET_AVG_STOCK(PRODUCT_CD, :B1, :B2)
FROM DUAL
)) AVG_STOCK
FROM PRODUCT
WHERE CATEGORY_CD = ’20’
GROUP BY PRODUCT_CD,
PRODUCT_NAME
;

 

2. Deterministic Function 사용

입력값이 동일하면 리턴값도 받드시 동일한 함수에서 사용할 수 있는데 이점을 이용해서
함수가 반복 호출될때 이전에 호출한 값이 호출되면 함수가 호출되지 않고
바로 값을 되돌려 줘서 함수호출 부하를 줄이는 것이다.

  • Deterministic 키워드는, 함수의 입력 값이 같다면 출력값도 항상 같음을 선언하려는 데 목적이 있다.
  • 이러한 본래 의미를 무시하고 캐싱 효과를 얻을 목적으로 함부로 Deterministic 함수로 선언하면 안된다.

Good Bad
CREATE OR REPLACE FUNCTION f1 (
  p1 NUMBER
) RETURN NUMBER DETERMINISTIC
IS
BEGIN
  RETURN p1 * 2;
END;
/
CREATE OR REPLACE FUNCTION lookup (
  l_input NUMBER
) RETURN VARCHAR2 DETERMINISTIC
IS 
BEGIN
  select value into l_output from LookupTable where key = l_input;
END;
/

  • Deterministic Function의 Cache 기능은 10g에서부터 지원된다.
  • 이전 버전에서 이 효과를 누리려면 (Scalar) Subquery를 사용한다.
  • Cache는 Query Level이 아닌 Fetch Level에서 이루어진다.
  • 따라서 Cache 효과를 누리려면 Fetch Array Size를 크게 지정해야 한다.

  •  

    반응형
    LIST
    반응형

    Redis란?

    Redis

    • Remote Dictionary Server의 약자
    • 오픈 소스 소프트웨어
    • 휘발성이면서 영속성을 가진 key-value 저장소

    Redis는 NoSQL

    NoSQL은 데이터 간의 관계를 정의하지 않고 고정된 스키마를 갖지 않는 새로운 형태의 데이터베이스로서, 관계형 데이터베이스(RDBMS)를 경량화한 데이터베이스 입니다. 관계형 데이터베이스의 특징 을 제거하고 만들어진 다른 모든 형태의 DBMS를 칭하 기도 하며, SQL 계열 질의어를 사용할 수 있다는 사실 을 강조한다는 면에서 “Not Only SQL”로 불리기도 합니다.

    Redis는 이러한 NoSQL의 종류 중 하나입니다.

    데이터 모델

    NoSQL이 가지고 있는 대표적인 데이터 모델은 아래와 같습니다.

    • Key-Value
      • 하나의 Key에 하나의 Value를 갖는 데이터 모델
      • Key로만 접근 가능
    • Column
      • 하나의 Key에 여러개의 Value를 갖을 수 있는 데이터 모델
      • 중첩된 HashMap 구조
    • Document
      • Value가 Json이나 XML Document를 갖는 데이터 모델
      • Value의 일부로 질의하고 일부만 가져올 수 있음
    • Graph
      • 관계에 특화된 모델
      • 노드와 간선에 대한 정보

    이 중 Redis는 Key-Value 데이터 모델을 사용합니다. 
    단순한 형태의 Key-Value 방식으로 빠른 속도를 지원할 수 있습니다.

    데이터 타입

    Redis는 key-value 데이터 모델에서 Value가 가질 수 있는 자료 구조를 제공합니다.

    제공되는 자료구조를 아래와 같습니다.

    • String
      • Command Docs : http://redis.io/commands#string
      • Text, 숫자 등 일반적인 Value
    • Set
      • Command Docs : http://redis.io/commands#set
      • Value가 Set 자료구조가 되므로, 하나의 Key 값에 여러 값을 Set 자료구조를 통해 저장 가능
      • Set간의 집합 연산을 제공
    • Sorted Set
      • Command Docs : http://www.redis.io/commands#sorted_set
      • score라는 필드가 추가되어 정렬의 기준이 됨.
      • score를 통해 질의 가능
      • 그 외에는 위의 Set과 같음
    • Hashes

      • Command Docs : https://redis.io/commands#hash
      • Value가 Map 자료구조와 같은 Key/Value 형태가 됨
        • 하나의 Key에 여러개의 필드를 갖는 구조가 됨
    • List

      • Command Docs : https://redis.io/commands#list
      • Value가 linkedList 자료구조가 됨
        • Push/Pop 연산 가능
        • index 활용 질의 가능

    휘발성

    스티븐 옌은 자신의 블로그의 글 “NoSQL is a Horseless Carriage”에서 Redis를 Store가 아닌 Cache로 구분했습니다.(A Yes for a NoSQL Taxonomy 참고)

    Reids는 디스크 기반이 아닌 메모리에 데이터를 read/write하는 in-memory 솔루션이기 때문입니다.

    메모리 기반이기 때문에 갖을 수 있는 장점은 아래와 같습니다.

    • 메모리에 데이터를 read/write 하기 때문에 매우 빠른 속도를 보장할 수 있습니다.
    • 모든 데이타가 메모리 안에 있기 때문에 캐시 관점에서 매우 유용합니다.
    • Cache 방식을 통한 DB 부하 감소

    영속성

    레디스는 지속성을 보장하기 위해 데이터를 DISK에 저장할 수 있습니다. 서버가 내려가더라도 DISK에 저장된 데이터를 읽어서 메모리에 로딩을 합니다.

    데이터를 DISK에 저장하는 방식은 크게 두 가지 방식이 있습니다.

    • snapshotting (RDB) 방식
      • 순간적으로 메모리에 있는 내용을 DISK에 전체를 옮겨 담는 방식
    • AOF(Append On File) 방식
      • redis의 모든 write/update 연산 자체를 모두 log 파일에 기록하는 형태

    Spring Boot 시작

    2017-08-07 Spring Boot Version으로 재작성

    build.gradle

    compile("org.springframework.boot:spring-boot-starter-data-redis")
    

    spring-boot-starter-data-redis

    Spring Boot 에서 제공하는 Starter 로 Redis 를 사용함에 필요한 Dependency 와 Configuration 을 제공합니다.

    Dependency

    • spring-data-redis : 스프링에서 공식 지원하는 Dependency로 Redis Client와 연동 가능한 높은 레벨의 RedisTemplate 추상화를 제공합니다.

    • jedis : 가장 많이 사용되고 있는 Java Client로 가장 활발한 오픈소스이며, 레디스에서 공식 추천하고 있는 Client 중 하나입니다. [참고]

    Auto Configuration

    application.properteis

    spring.redis.host = 127.0.0.1
    spring.redis.password=
    spring.redis.port=6379
    
    • JedisConnectionFactory : Redis 연동

    • RedisTemplate : Redis Command 를 도와주는 Template

    Operations

    Operation은 사용할 데이터 타입에 따라 다르게 사용해야 합니다. Operation들은 @Resources 어노테이션을 통해 선언해놓은 RedisTemplate로부터 주입 받을 수 있습니다.

    String

    @Resource(name="redisTemplate")
    private ValueOperations<String, String> valueOperations;
    

    Set

    @Resource(name="redisTemplate")
    private SetOperations<String, String> setOperations;
    

    Sorted Set

    @Resource(name="redisTemplate")
    private ZSetOperations<String, String> zSetOperations;
    

    Hashes

    @Resource(name="redisTemplate")
    private HashOperations<String, String, String> hashOperations;
    

    Hashes

    @Resource(name="redisTemplate")
    private ListOperations<String, String> listOperations;
    

    Operation 사용 예제

    적절하지는 않지만, 다양한 데이터 타입을 사용하는 간단한 예제를 만들어보았습니다.

    Redis에 간단한 자기소개 정보를 저장해두고, 특정 사건이 발생함에 따라 변하는 변화를 Redis Operation으로 풀어보았습니다~

    특정 사건은 선임의 이직!

    bye

    SpringBootRedisApplicationTests.java

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = SpringBootRedisApplication.class)
    public class SpringBootRedisApplicationTests {
    
        @Resource(name="redisTemplate")
        private ValueOperations<String, String> valueOperations;
    
        @Resource(name = "redisTemplate")
        private ListOperations<String, String> listOperations;
    
        @Resource(name = "redisTemplate")
        private HashOperations<String, String, String> hashOperations;
    
        @Resource(name = "redisTemplate")
        private SetOperations<String, String> setOperations;
    
        @Resource(name="redisTemplate")
        private ZSetOperations<String, String> zSetOperations;
    

    테스트가 아니라 간단히 예제를 보여줄 예정이여서 Application의 Config를 그대로 사용하려고 합니다.

    Data 삽입

    @Before
    public void init() {
        //list put
        listOperations.rightPush("test:task", "자기소개");
        listOperations.rightPush("test:task", "취미소개");
        listOperations.rightPush("test:task", "소망소개");
        listOperations.rightPush("test:task", "선임이직");
        //hash put
        hashOperations.put("test:user:kingbbode", "name", "권뽀대");
        hashOperations.put("test:user:kingbbode", "age", "28");
        //set put
        setOperations.add("test:user:kingbbode:hobby", "개발");
        setOperations.add("test:user:kingbbode:hobby", "잠");
        setOperations.add("test:user:kingbbode:hobby", "옷 구경");
        //zset
        zSetOperations.add("test:user:kingbbode:wish", "배포한 것에 장애없길", 1);
        zSetOperations.add("test:user:kingbbode:wish", "배포한거 아니여도 장애없길", 2);
        zSetOperations.add("test:user:kingbbode:wish", "경력직 채용", 3);
        zSetOperations.add("test:user:kingbbode:wish", "잘자기", 4);
    }
    

    List는 Push를 통하여 데이터를 저장합니다. push에는 leftPush와 rightPush가 있습니다. Stack이나 Queue로 활용 가능합니다.

    Hash는 Map 자료형과 사용이 거의 비슷합니다. key-field-value를 작성하여 데이터를 삽입합니다.

    Set은 같은 Key에 여러 Value를 작성할 수 있습니다.

    ZSet은 Value에 Score를 포함하여 데이터를 삽입하였습니다.

    모두 네이밍을 통해서 알만한 메서드를 operation에서 제공해주고 있습니다.

    데이터 조회

    @Test
    public void redisTest1() {
        String task = listOperations.leftPop("test:task");
        StringBuilder stringBuilder = new StringBuilder();
        while (task != null) {
            switch (task) {
                case "자기소개":
                    Map<String, String> intro = hashOperations.entries("test:user:kingbbode");
                    stringBuilder.append("\n******자기소개********");
                    stringBuilder.append("\n이름은 ");
                    stringBuilder.append(intro.get("name"));
                    stringBuilder.append("\n나이는 ");
                    stringBuilder.append(intro.get("age"));
                    break;
                case "취미소개":
                    Set<String> hobbys = setOperations.members("test:user:kingbbode:hobby");
                    stringBuilder.append("\n******취미소개******");
                    stringBuilder.append("취미는");
                    for (String hobby : hobbys) {
                        stringBuilder.append("\n");
                        stringBuilder.append(hobby);
                    }
                    break;
                case "소망소개":
                    Set<String> wishes = zSetOperations.range("test:user:kingbbode:wish", 0, 2);
                    stringBuilder.append("\n******소망소개******");
                    int rank = 1;
                    for (String wish : wishes){
                        stringBuilder.append("\n");
                        stringBuilder.append(rank);
                        stringBuilder.append("등 ");
                        stringBuilder.append(wish);
                        rank++;
                    }
                    break;
                case "선임이직":
                    stringBuilder.append("\n!!! 믿었던 선임 이직");
                    zSetOperations.incrementScore("test:user:kingbbode:wish", "경력직 채용", -1);
                    listOperations.rightPush("test:task", "소망소개");
                    break;
                default:
                    stringBuilder.append("nonone");
    
            }
            task = listOperations.leftPop("test:task");
        }
        System.out.println(stringBuilder.toString());
    }
    

    List는 Pop를 통하여 좌측 노드부터 데이터를 꺼냈습니다. 데이터를 rightPush 했으므로 leftPop을 사용함으로써 Queue처럼 사용하고 있습니다.

    Hash는 entries를 통해 데이터를 Map 자료형으로 가져올 수 있습니다.

    Set의 Value 안의 값들을 member라고 합니다. 그래서 members를 통해 해당 Key의 값들을 Set 자료형으로 가져올 수 있습니다.

    ZSet은 range를 통해 정해진 Rank 범위의 데이터를 가져올 수 있습니다. score를 기준으로 오름차순으로 데이터를 정렬합니다.

    선임이직이라는 이벤트가 발생시, 경력직 채용의 score를 -1하여 rank를 높이도록 해두었습니다. zset의 incrementScore를 사용했습니다. 그리고 소망이 변경되었으니 소망을 한번 더 말해도록 task를 추가했습니다.

    출력결과는 원하는 작업을 잘 수행해서 나옵니다!

    결과

    GitHub Source



    출처: http://kingbbode.tistory.com/25 [개발노트 - kingbbode]

    반응형
    LIST
    반응형

    소스 ==>

    public class Foo {
      public static void main(String[] args) {

        String s  = "Abc abC ABC abc"; // 원본 문자열
        String s2;

        System.out.println("원본:    " + s);
        System.out.println(); // 줄바꿈


        s2 = s.replaceFirst("(?i)abc", "ZZZ");
        System.out.println("치환(1): " + s2);


        s2 = s.replaceAll("(?i)abc", "ZZZ");
        System.out.println("치환(2): " + s2);

      }
    }


    결과 ==>

    원본:    Abc abC ABC abc

    치환(1): ZZZ abC ABC abc
    치환(2): ZZZ ZZZ ZZZ ZZZ

    반응형
    LIST
    반응형

    <!DOCTYPE html>

    <html>

    <head>

    <script>

    var a = 'test';

        var test = 'a';

        var temp = {};

        eval("temp."+a+"=test");

        console.log(temp);

    </script>

    <title>Page Title</title>

    </head>

    <body>


    <h1>This is a Heading</h1>

    <p>This is a paragraph.</p>


    </body>

    </html>



    반응형
    LIST

    + Recent posts