"웹 스케일"이라는 용어는 최근에 과장되었으며 사람들은 애플리케이션 아키텍처를 확장하여 시스템을보다 "광범위한 도메인"으로 만들고 있습니다. 그러나 전체 도메인은 정확히 무엇입니까? 아니면 전체 도메인을 보장하는 방법?
가장 과장된 스케일링 하중이 가장 인기있는 도메인입니다. 예를 들어, 단일 사용자 액세스를 지원하는 시스템은 10, 100 또는 1 백만 명의 사용자 액세스를 지원할 수 있습니다. 이상적으로는, 우리의 시스템은 가능한 한 "무국적"으로 유지되어야합니다. 상태가 존재해야하더라도 네트워크의 다른 처리 단자에서 변환 및 전송 될 수 있습니다. 하중이 병목 현상이되면 지연이 없을 수 있습니다. 따라서 단일 요청의 경우 50 ~ 100 밀리 초를 소비하는 것이 허용됩니다. 이것을 스케일링이라고합니다.
확장은 전체 도메인 최적화에서 완전히 다르게 수행됩니다. 예를 들어, 하나의 데이터가 성공적으로 처리되도록하는 알고리즘은 10, 100 또는 1 백만 개의 데이터를 성공적으로 처리 할 수 있습니다. 이벤트 복잡성 (큰 O 기호) 은이 메트릭 유형이 실현 가능 여부에 관계없이 최상의 설명입니다. 대기 시간은 성능 스케일링 킬러입니다. 동일한 기계에서 모든 작업을 처리하기 위해 최선을 다할 것입니다. 이것을 스케일링이라고합니다.
파이가 하늘에서 떨어질 수 있다면 (물론 이것은 불가능합니다) 수평 팽창과 수직 확장을 결합 할 수 있습니다. 그러나 오늘날 우리는 효율성을 향상시키는 다음과 같은 간단한 방법 만 소개 할 것입니다.
Java 7의 Forkjoinpool과 Java 8의 병렬 데이터 스트림 (ParallelStream)은 병렬 처리에 도움이됩니다. 모든 프로세서가 동일한 메모리에 액세스 할 수 있기 때문에 멀티 코어 프로세서에 Java 프로그램을 배포 할 때 특히 분명합니다.
따라서이 병렬 처리의 근본적인 이점은 네트워크 전체의 다른 기계의 스케일링에 비해 대기 시간을 거의 완전히 제거하는 것입니다.
그러나 병렬 처리의 효과에 혼란스러워하지 마십시오! 다음 두 가지 점을 명심하십시오.
알고리즘 복잡성을 줄이는 것은 의심 할 여지없이 성능을 향상시키는 가장 효과적인 방법입니다. 예를 들어, HashMap 인스턴스 Xookup () 메소드의 경우 이벤트 복잡성 O (1) 또는 공간 복잡성 O (1)가 가장 빠릅니다. 그러나이 상황은 종종 불가능합니다. 쉽게 달성 할 수는 없습니다.
알고리즘의 복잡성을 줄일 수없는 경우 알고리즘에서 핵심 사항을 찾고 방법을 개선하여 성능을 향상시킬 수도 있습니다. 다음 알고리즘 다이어그램이 있다고 가정합니다.
이 알고리즘의 전체 시간 복잡성은 O (N3)이며 별도의 액세스 순서로 계산하면 복잡성이 O (N X O x P)라고 결론을 내릴 수도 있습니다. 그러나 어쨌든, 우리는이 코드를 분석 할 때 몇 가지 이상한 시나리오를 찾을 것입니다.
생산 데이터 참조가 없으면 "높은 오버 헤드 작업"을 최적화해야한다는 결론을 쉽게 도출 할 수 있습니다. 그러나 우리가 만든 최적화는 전달 된 제품에 영향을 미치지 않았습니다.
최적화 된 황금률은 다음과 같습니다.
그게 전부 이론입니다. 오른쪽 지점에서 문제가 발생한다고 가정하면, 제품의 간단한 처리가 많은 시간으로 인해 응답이 상실 될 수 있습니다 (N, O 및 P의 값이 매우 크다고 가정 함). 기사에 언급 된 왼쪽 지점의 시간 복잡성은 O (n3)입니다. 여기서 이루어진 노력은 확장 될 수 없지만 사용자의 시간을 절약하고 나중에까지 어려운 성능 개선을 지연시킬 수 있습니다.
Java 성능 향상을위한 10 가지 팁은 다음과 같습니다.
1. StringBuilder를 사용하십시오
StingBuilder는 Java 코드에서 기본적으로 사용해야하며 + 연산자를 피해야합니다. 어쩌면 당신은 다음과 같은 StringBuilder의 구문 설탕에 대해 다른 의견을 가질 것입니다.
문자열 x = "a" + args.length + "b";
다음과 같이 컴파일됩니다.
0 New Java.lang.stringBuilder [16] 3 Dup4 ldc <String "a"> [18] 6 Invokespecial java.lang.stringBuilder (java.lang.string) [20] 9 Aload_0 [Arraylength11 invokevirtual java.lang.stringbuilder .append (int). java.lang.stringBuilder [23] 14 LDC <String "B"> [27] 16 InvokeVirtual java.lang.springBuilder.append (java.lang.string) : java.lang.stringbuilder [29] 19 InvokeVirtual java.lang.stringbuilder.tostring. [32] 22 Store_1 [x]
그러나 정확히 무슨 일이 일어 났습니까? 다음 섹션을 사용하여 다음 섹션을 사용해야합니까?
문자열 x = "a" + args.length + "b"; if (args.length == 1) x = x + args [0];
이제 우리는 두 번째 StringBuilder를 사용했는데, 이는 힙에 여분의 메모리를 소비하지 않고 GC에 압력 을가합니다.
StringBuilder x = new StringBuilder ( "a"); x.append (args.length); x.append ( "b"); if (args.length == 1); x.append (args [0]);
위의 예에서, 인스턴스를 암시 적으로 생성하기 위해 Java 컴파일러에 의존하는 경우, 컴파일 된 효과는 StringBuilder 인스턴스가 사용되는지 여부와 관련이 없습니다. 기억하십시오 : Nope 브랜치에서 각 CPU 사이클에 소비 된 시간은 StringBuilder에 대한 GC 또는 기본 공간을 할당하는 데 소비되며 N X O X P 시간을 낭비하고 있습니다.
일반적으로 StringBuilder를 사용하는 것이 + 연산자를 사용하는 것보다 낫습니다. 가능한 경우 String이 추가 리소스를 소비하기 때문에 여러 메소드에서 참조를 전달 해야하는 경우 StringBuilder를 선택하십시오. Jooq는 복잡한 SQL 문을 생성 할 때이 방법을 사용합니다. 추상 구문 트리의 전체 SQL 패스 스루 중에 하나의 StringBuilder 만 사용됩니다.
더 비극적 인 점은 여전히 StringBuffer를 사용하는 경우 StringBuffer 대신 StringBuilder를 사용한다는 것입니다. 결국, 문자열을 동기화 해야하는 경우는 많지 않습니다.
정규 표현은 사람들에게 빠르고 쉽다는 인상을줍니다. 그러나 Nope 지점에서 정규 표현을 사용하는 것이 최악의 결정이 될 것입니다. 컴퓨팅 집약적 코드에서 정규식을 사용해야하는 경우 패턴을 반복적으로 컴파일하지 않도록 패턴을 캐시하십시오.
정적 최종 패턴 Heavy_Regex = Pattern.comPile ( "((((((())*y)*z)))*");
다음과 같은 간단한 정규 표현 만 사용하는 경우 :
문자열 [] parts = iPaddress.split ( "//.");
이것은 일반적인 char [] 배열 또는 인덱스 기반 작업을 사용하는 것이 가장 좋습니다. 예를 들어, 가독성이 좋지 않은 다음 코드는 실제로 동일한 역할을합니다.
int length = iPaddress.length (); int 오프셋 = 0; int part = 0; for (int i = 0; i <length; i ++) {if (i == 길이 -1 || ipaddress.charat (i+1) == '.위의 코드는 또한 조기 최적화가 의미가 없음을 보여줍니다. Split () 메소드와 비교할 때이 코드는 유지 관리가 적습니다.
도전 : 똑똑한 친구들이 더 빠른 알고리즘을 만들 수 있습니까?
정규식은 매우 유용하지만 사용하면 가격을 지불해야합니다. 특히 Nope 지점에 깊은 곳에있을 때는 모든 비용으로 정규 표현을 사용하지 않아야합니다. 또한 string.replaceall () 또는 String.split ()와 같은 정규 표현식을 사용하는 다양한 JDK 문자열 메소드에주의하십시오. Apache Commons Lang과 같은보다 인기있는 개발 라이브러리를 사용하여 문자열 작업을 수행 할 수 있습니다.
이 제안은 일반적인 경우에는 적용되지 않지만 Nope Branch의 깊은 시나리오에는 적용됩니다. 그럼에도 불구하고 당신은 무언가를 이해해야합니다. Java 5 형식 루프 쓰기 방법은 매우 편리하여 다음과 같은 내부 루프 방법을 잊을 수 있습니다.
for (문자열 값 : 문자열) {// 여기에서 유용한 일을합니다}코드 가이 루프로 실행될 때마다 문자열 변수가 반복적 인 경우 코드는 반복자 인스턴스를 자동으로 생성합니다. ArrayList를 사용하는 경우 가상 머신은 3 개의 정수 유형 메모리를 힙의 객체에 자동으로 할당합니다.
개인 클래스 ITR은 반복자 <e> {int cursor를 구현합니다. int lastret = -1; int exclingModCount = modCount; // ...다음과 같은 동등한 루프 방법을 사용하여 루프의 위를 교체 할 수 있습니다. 스택에 성형 수술을 "낭비"하는 것만으로도 비용 효율적입니다.
int size = strings.size (); for (int i = 0; i <size; i ++) {문자열 값 : strings.get (i); // 여기에서 유용한 일을}루프의 문자열 값이 크게 변경되지 않으면 배열을 사용하여 루프를 구현할 수도 있습니다.
for (문자열 값 : StringArray) {// 여기에서 유용한 일을합니다}쉬운 읽기와 쓰기의 관점에서든, API 디자인의 관점에서든 반복자, 반복 가능한 인터페이스 및 외식 루프는 매우 유용합니다. 그러나 비용으로, 사용할 때는 각 루프 하위의 힙에 추가 객체가 생성됩니다. 루프를 여러 번 실행하려면 의미없는 인스턴스를 생성하지 않도록주의하십시오. 기본 포인터 루프 방법을 사용하여 위에서 언급 한 반복자, 반복 가능한 인터페이스 및 Foreach 루프를 대체하는 것이 가장 좋습니다.
위의 내용 (특히 반복자를 포인터로 대체)에 반대하는 일부 의견은 Reddit에서 자세한 내용에 대해 설명합니다.
일부 방법은 비싸다. Nope 지점을 예로 들어, 우리는 잎의 관련 방법을 언급하지 않았지만 이것을 찾을 수 있습니다. JDBC 드라이버가 resultset.wasnull () 메소드의 반환 값을 계산하는 데 모든 어려움을 극복해야한다고 가정하십시오. 우리가 구현하는 SQL 프레임 워크는 다음과 같습니다.
if (type == integer.class) {result = (t) wasnull (rs, integer.valueof (rs.getint (index));} // 그리고 ... 정적 최종 <t> t wasnull (resultet rs, t value)는 sqlexception {return rs.wasnull ()? NULL : Value;}위의 논리에서 resultSet.wasNull () 메소드는 결과 세트에서 int 값을 얻을 때마다 호출되지만 getInt () 메소드는 다음과 같이 정의됩니다.
반환 유형 : 가변 값; SQL 쿼리 결과가 NULL 인 경우 0을 반환하십시오.
따라서 개선하는 간단하고 효과적인 방법은 다음과 같습니다.
static final <t restends number> t wasnull (resultset rs, t value)은 sqlexception {return (value == null || (value.intValue () == 0 && rs.wasnull ()))? NULL : Value;}이것은 산들 바람입니다.
캐시 방법 호출 잎 노드에서 높은 오버 헤드 메소드를 교체하거나 메소드 규칙이 허용되는 경우 높은 오버 헤드 메소드를 호출하지 마십시오.
위의 내용은 Jooq의 예제에서 많은 수의 제네릭을 사용하여 바이트, 짧은, int 및 긴 래퍼 클래스를 사용합니다. 그러나 적어도 제네릭은 Java 10 또는 Valhalla 프로젝트에 전문화 될 때까지 코드 제한이되어서는 안됩니다. 다음 방법으로 대체 할 수 있기 때문입니다.
// 힙 정수에 저장된 I = 817598;
...이 방법을 쓰면 :
// 스택에 저장 INT I = 817598;
배열을 사용할 때 상황이 악화 될 수 있습니다.
// 힙 정수에서 세 개의 객체가 생성되었습니다 [] i = {1337, 424242};...이 방법을 쓰면 :
// 힙에 하나의 객체 만 생성됩니다 int [] i = {1337, 424242};우리가 Nope 지점에 깊이있을 때 포장 수업을 사용하지 않도록 최선을 다해야합니다. 이를 수행하는 단점은 GC에 많은 압력 을가한다는 것입니다. GC는 포장 클래스에서 생성 된 물체를 지우기 위해 매우 바쁠 것입니다.
따라서 효과적인 최적화 방법은 기본 데이터 유형, 고정 길이 배열을 사용하고 일련의 분할 변수를 사용하여 배열에서 객체의 위치를 식별하는 것입니다.
LGPL 프로토콜을 따르는 Trove4J는 Java Collection Class 라이브러리로, 쉐이핑 어레이 INT []보다 더 나은 성능 구현을 제공합니다.
다음과 같은 예외는이 규칙에 대한 것입니다. 부울 및 바이트 유형은 JDK가 캐시 메소드를 제공 할 수 있도록 충분하지 않기 때문입니다. 우리는이 방법을 쓸 수 있습니다.
부울 a1 = true; // ... 구문 설탕 : 부울 a2 = boolean.valueof (true); 바이트 b1 = (바이트) 123; // ... BYTE B2 = BYTE.VALUEOF ((BYTE) 123);
다른 기본 유형의 정수는 또한 숯, 짧은, int 및 길과 같은 비슷한 상황을 가지고 있습니다.
생성자를 호출 할 때 이러한 정수 원시 유형을 자동으로 상자에 넣지 않거나 thetype.valueof () 메소드를 호출하십시오.
또한 힙에 생성되지 않은 인스턴스를 얻으려면 래퍼 클래스에서 생성자를 호출하지 마십시오. 이 작업의 장점은 동료들에게 거대한 4 월 바보의 날 농담을주는 것입니다.
물론, 오프 펙 기능 라이브러리를 경험하고 싶다면 가장 낙관적 인 로컬 솔루션보다는 많은 전략적 결정과 혼합 될 수 있습니다. Peter Lawrey와 Ben Cotton이 작성한 비 Heap Storage에 관한 흥미로운 기사를 보려면 : OpenJDK 및 Hashmap- 재향 군인이 안전하게 마스터하고 (비자식 스토리지!) 새로운 기술을 클릭하십시오.
오늘날 Scala와 같은 기능적 프로그래밍 언어는 재귀를 장려합니다. 재귀는 일반적으로 개별적으로 최적화 된 개인으로 분해 될 수있는 꼬리 수수료를 의미하기 때문입니다. 사용하는 프로그래밍 언어가이를 지원할 수 있다면 더 좋습니다. 그럼에도 불구하고 알고리즘의 약간의 조정이 꼬리 재귀를 일반 재귀로 바꿀 수 있도록주의하십시오.
컴파일러가 이것을 자동으로 감지 할 수 있기를 바랍니다. 그렇지 않으면 몇 가지 로컬 변수로 수행 할 수있는 작업에 대해 많은 스택 프레임을 낭비했을 것입니다.
이 섹션에는 재귀 대신 Nope 지점에서 가능한 한 반복을 제외하고는 할 말이 없습니다.
키 값 쌍으로 저장된지도를 반복하려면 다음 코드에 대한 좋은 이유를 찾아야합니다.
for (k key : map.keyset ()) {v value : map.get (key);}다음과 같은 글쓰기 방법은 말할 것도 없습니다.
for (Entry <k, v> entry : map.entryset ()) {k key = Entry.getKey (); v value = actor.getValue ();}Nope Branch를 사용하면주의해서지도를 사용해야합니다. O (1)의 시간 복잡성이있는 것처럼 보이는 많은 액세스 작업은 실제로 일련의 작업으로 구성되어 있기 때문입니다. 그리고 액세스 자체는 무료가 아닙니다. 적어도지도를 사용해야하는 경우 entryset () 메소드를 사용하여 반복해야합니다! 이런 식으로, 우리는 map.entry 인스턴스에만 액세스하려고합니다.
키 값 쌍의 형태로 맵을 반복 해야하는 경우 Entryset () 메소드를 사용하십시오.
8. 사용 열거 또는 열거
구성 맵을 사용할 때와 같은 경우 맵에 저장된 키 값을 미리 알 수 있습니다. 이 키 값이 매우 작 으면 일반적으로 사용하는 해시 또는 해시 맵을 사용하는 대신 enumset 또는 enummap을 사용하는 것을 고려해야합니다. 다음 코드는 명확한 설명을 제공합니다.
개인 과도 객체 [] vals; public v put (k key, v value) {// ... int index = key.ordinal (); vals [index] = masknull (value); // ...}이전 코드의 주요 구현은 해시 테이블 대신 배열을 사용한다는 것입니다. 특히 맵에 새 값을 삽입 할 때 각 열거 유형에 대해 컴파일러에 의해 생성 된 일정한 시퀀스 번호를 얻기 만하면됩니다. 글로벌 맵 구성이있는 경우 (예 : 하나의 인스턴스 만) EnumMap은 액세스 속도가 증가하는 압력 하에서 해시 맵보다 뛰어난 성능을 달성합니다. 그 이유는 EnumMap이 Hashmap보다 하나의 비트 힙 메모리를 사용하고 Hashmap은 각 키 값에 대한 hashcode () 메소드 및 equals () 메소드를 호출하기 때문입니다.
열거와 열거는 친한 친구입니다. 열거 형 구조와 유사한 주요 값을 사용하는 경우 이러한 주요 값을 열거 유형으로 선언하고 열거 키로 사용하는 것을 고려해야합니다.
EnumMap을 사용할 수없는 경우 적어도 hashcode () 및 equals () 메소드를 최적화해야합니다. High-Overhead Equals () 메소드에 불필요한 호출을 방지하기 때문에 양호한 hashcode () 메소드가 필요합니다.
각 클래스의 상속 구조에서 쉽게 허용되는 간단한 객체가 필요합니다. Jooq의 org.jooq.table이 어떻게 구현되는지 살펴 보겠습니다.
가장 간단하고 빠른 hashcode () 구현 방법은 다음과 같습니다.
// 일반 표의 기본 구현 : @OverRidePublic int HashCode () {// [#1938] 표준 QueryParts와 비교하여보다 효율적인 해시 코드 () 구현입니다. return name.hashcode ();}이름은 테이블 이름입니다. 테이블 이름은 일반적으로 데이터베이스에서 고유하기 때문에 스키마 또는 기타 테이블 속성을 고려할 필요조차 없습니다. 변수 이름은 문자열이며 자체가 이미 hashcode () 값을 캐시했습니다.
AbstractQueryPart에서 상속 된 AbstractTable은 Abstract 구문 트리 요소의 기본 구현이기 때문에이 코드의 의견은 매우 중요합니다. 일반적인 초록 구문 트리 요소에는 속성이 없으므로 hashcode () 메소드 구현 최적화에 대한 환상을 가질 수 없습니다. 덮어 쓰기 hashcode () 메소드는 다음과 같습니다.
// AbstractQueryPart 일반적인 초록 구문 트리 기본 구현 : @overridepublic int hashcode () {// 이것은 작동하지 않는 기본 구현입니다. // 특정 구현 서브 클래스는 성능을 향상시키기 위해이 메소드를 무시해야합니다. return create (). renderInlined (this) .hashCode ();}다시 말해, 전체 SQL 렌더링 워크 플로우는 일반적인 초록 구문 트리 요소의 해시 코드를 계산하도록 트리거됩니다.
equals () 메소드는 훨씬 더 흥미 롭습니다.
// AbstractTable General Table의 기본 구현 : @OverridePublic Boolean Equals (객체) {if (this == that) {return true;} // [#2144] High-Over-Head AbstractQueryPart.equals () 메서드를 호출하기 전에 // 객체가 동일하지 않은지 조기에 알 수 있습니다. if (AbstractTable의 인스턴스) {if (stringUtils.equals (이름, (((((() actracttable <?>)))))) .name)))) {return super.equals (that);} return false;} return false;}첫째, if : if : equals () 메소드를 너무 일찍 사용하지 마십시오.
참고 : 인스턴스의 인스턴스를 너무 일찍 사용하여 호환 가능한 유형을 확인하는 경우 다음 조건에는 실제로 인수 == NULL이 포함됩니다. 이전 블로그에서 이미 설명했는데 10 개의 절묘한 Java 코딩 모범 사례를 참조하십시오.
위의 상황을 비교 한 후에는 결론을 도출 할 수 있어야합니다. 예를 들어, jooq의 테이블 .equals () 메소드는 두 테이블이 동일한 지 비교하는 데 사용됩니다. 특정 구현 유형에 관계없이 필드 이름이 동일해야합니다. 예를 들어 다음 두 요소는 동일 할 수 없습니다.
들어오는 매개 변수가 인스턴스 자체 (this)와 같은지 쉽게 결정할 수 있다면 결과가 False 인 경우 작업을 포기할 수 있습니다. 반환 결과가 참이면 부모 클래스의 슈퍼 구현을 더 판단 할 수 있습니다. 비교 된 대부분의 객체가 동일하지 않은 경우 CPU 실행 시간을 저장하기 위해 가능한 한 빨리 방법을 종료 할 수 있습니다.
일부 물체는 다른 물체보다 유사성이 높습니다.
Jooq에서는 대부분의 테이블 인스턴스가 Jooq의 코드 생성기에 의해 생성되며 이러한 인스턴스의 equals () 메소드는 깊이 최적화되었습니다. 수십 개의 다른 테이블 유형 (파생 테이블), 테이블 값 기능, 어레이 테이블, 결합 된 테이블, 피벗 테이블, 공통 테이블 표현식 등의 기본 구현을 유지 관리합니다.
마지막으로, Java뿐만 아니라 모든 언어에 적용될 수있는 또 다른 상황이 있습니다. 또한, 우리가 이전에 연구 한 NOPE 지점은 O (n3)에서 O (n log n)까지의 이해에 도움이 될 것입니다.
불행히도, 많은 프로그래머는 간단한 로컬 알고리즘을 사용하여 문제를 고려합니다. 그들은 단계별로 문제를 해결하는 데 사용됩니다. 이것은 "예/또는"명령의 형태입니다. 이 프로그래밍 스타일은 순수한 명령 프로그래밍에서 객체 지향 프로그래밍으로 기능 프로그래밍으로 변환 할 때 "더 큰 그림"을 쉽게 모델링 할 수 있지만 이러한 스타일에는 SQL 및 R에만 존재하는 것이 부족합니다.
선언 프로그래밍.
SQL에서는 알고리즘의 영향을 고려하지 않고 데이터베이스에 필요한 효과를 선언 할 수 있습니다. 데이터베이스는 제약 조건, 키, 인덱스 등과 같은 데이터 유형에 따라 최상의 알고리즘을 채택 할 수 있습니다.
이론적으로, 우리는 먼저 SQL과 관계형 계산 후 기본 아이디어를 가졌습니다. 실제로 SQL 공급 업체는 지난 수십 년 동안 오버 헤드 기반 효율적인 최적화기 (비용 기반 옵티 미셔)를 구현했습니다. 그런 다음 2010 년 버전에서 마침내 SQL의 모든 잠재력을 발견했습니다.
그러나 설정 방법을 사용하여 SQL을 구현할 필요는 없습니다. 모든 언어 및 라이브러리는 세트, 컬렉션, 가방 및 목록을 지원합니다. 세트 사용의 주요 이점은 코드를 간결하고 명확하게 만들 수 있다는 것입니다. 예를 들어 다음 글쓰기 방법 :
SOMESET은 어떤 사람을 교차시킵니다
대신에
// Java 8의 이전 작성 방법 설정 결과 = new Hashset (); for (object emplate : someSet) if (someSet.contains (후보)) result.add (후보); // Java 8을 사용하더라도 도움이되지는 않지만 그다지 도움이되지는 않습니다.
어떤 사람들은 기능 프로그래밍과 Java 8에 대해 다른 의견을 가질 수 있으며, 이는 더 간단하고 간단한 알고리즘을 작성하는 데 도움이 될 수 있습니다. 그러나이 견해가 반드시 사실은 아닙니다. 명령 적 Java 7 루프를 Java 8의 스트림 컬렉션으로 변환 할 수 있지만 여전히 동일한 알고리즘을 사용합니다. 그러나 SQL 스타일 표현식은 다릅니다.
SOMESET은 어떤 사람을 교차시킵니다위의 코드는 다른 엔진에서 1000 개의 다른 구현을 가질 수 있습니다. 오늘 우리가 공부하고있는 것은 교차 작업을 호출하기 전에 두 세트를 열거로 자동 변환하는 것입니다. 심지어 기본 stream.parallel () 메소드를 호출하지 않고 병렬 교차 작업을 수행 할 수 있습니다.
이 기사에서는 Nope Branching에 대한 최적화에 대해 논의합니다. 예를 들어, 높은 복잡성 알고리즘에 깊이 빠져 있습니다. Jooq의 개발자로서 우리는 SQL 생성을 최적화하게되어 기쁩니다.
Jooq는 "먹이 사슬의 바닥"에 있습니다. 왜냐하면 JVM을 떠나 DBM을 입력 할 때 컴퓨터 프로그램에서 마지막 API이기 때문입니다. 먹이 사슬의 맨 아래에 위치한 것은 Jooq에서 실행될 때 모든 라인이 n x o x p 시간을 소비한다는 것을 의미하므로 가능한 한 빨리 최적화하고 싶습니다.
우리의 비즈니스 논리는 Nope 지점만큼 복잡하지 않을 수 있습니다. 그러나 기본 프레임 워크는 매우 복잡 할 수 있습니다 (로컬 SQL 프레임 워크, 로컬 라이브러리 등). 따라서 오늘날 언급 된 원칙을 따라야하며 Java Mission Control 또는 기타 도구를 사용하여 최적화가 필요한 영역이 있는지 확인해야합니다.
원본 링크 : Jaxenter 번역 : importnew.com- 항상 도로 번역 링크 : http://www.importnew.com/16181.html