우지혜
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 10 실행 계획 ## 10.1 통계 정보 - MySQL 8.0 부터는 히스토그램 도입 - MySQL 5.7 버전에서 지원했던 테이블과 인덱스에 대한 개괄적인 정보 + 데이터 칼럼의 분포값 정보 -> 더 정확한 실행계획 선택 가능 ### 10.1.1 테이블 및 인덱스 통계 정보 #### MySQL 서버의 통계 정보 - 휘발성 VS 영구성 - MySQL 5.6 이전 : 휘발성 - 메모리에만 관리 - SHOW INDEX 명령으로만 테이블의 인덱스 칼럼 분포도를 확인할 수 있었음 - MySQL 5.6 부터 : 영구성 - InnoDB 스토리지 엔진 사용하는 테이블에 대한 통계 정보를 영구적으로 관리할 수 있음 - mysql 데이터베이스의 innodb_index_stats 테이블과 innodb_table_stats 테이블로 관리 가능 - 핵심 : 이제 서버 재시작해도 기존 통계 정보 유지할 수 있게 되었다 - `STATS_PERSISTENT` 옵션 : 영구적으로 통계 정보를 보관할지 결정 - 통계 정보 갱신 (398p) - MySQL 5.6 이전 : 자동 갱신 - 통계 정보가 갱신되면 쿼리 실행 계획 갑자기 달라질 수 있음 - 통계정보를 바탕으로 실행계획을 수립하기 때문 MySQL 서버가 갑자기 실행 계획을 다르게 설정(예측 불허) - MySQL 5.6 부터 : 수동 갱신 가능 + 자동일지도 선택가능 - 통계 정보 자동 수집 여부 결정 가능 by `STATS_AUTO_RECALC` 옵션 - 통계 정보 수집 시, 몇 개의 페이지 샘플링 할 것인지도 설정 가능 by 시스템 변수 - 갯수 늘리기 -> (+) 더 정확한 통계 정보 수집 가능 -> (-) 수집 시간 길어짐 - `innodb_stats_transient_sample_pages` : 8 기본 / 샘플링 분석 후 자동 통계 정보로 활용 - `innodb_stats_persistent_sample_pages` : 20 기본 / ANALYZE 명령 실행 후, 샘플링 분석 후 통계 정보 테이블에 저장 + 활용 ### 10.1.2 히스토그램 - MySQL 5.7 버전까지는 - 인덱스된 컬럼의 유니크한 값 개수 + 실제 인덱스의 일부 페이지 랜덤 get - MySQL 8.0 버전부터는 히스토그램 정보 활용 가능 #### 히스토그램 정보 수집 및 삭제 - 수집 - 히스토그램 정보는 컬럼 단위로 관리 - 수동 수집 - by `ANALYZE TABLE ... UPDATE HISTOGRAM` - (평소에는) 시스템 딕셔너리에 저장 - (MySQL 서버 실행시) information_schema 데이터베이스, column_statistics 테이블로 로드해서 사용 - 히스토그램 타입 (401p) - 싱글톤 히스토그램 : 칼럼값 개별 레코드 건수 기준 - 버킷 단위는 칼럼이 가지는 값 - 유니크한 값의 개수가 적은 경우 사용 -> 레인지 스캔인지 확인하는데 유용하지 않을까 - 높이 균형 히스토그램 : 컬럼값의 범위를 균등한 개수로 구분해서 관리 - 버킷 단위는 개수가 균등한 컬럼값의 범위 - (K) 기울기가 비슷하다 -> 각 범위가 비슷한 갯수를 가진다 - 비슷한 값들의 범위가 좁다 -> 밀도가 낮다 - [주의] 403 p 주의 참고 : 히스토그램 수집 시, 풀스캔 조심 (MySQL 8.0.19 미만의 경우) - 삭제 - 쿼리 처리의 성능에 영향 X -> 테이블 데이터를 참조하지 않고 딕셔너리 내용만 삭제하므로 - 실행 계획에 영향 O -> 실행 계획 수립시 사용하던 히스토그램이 삭제되었으므로 - MySQL 옵티마이저가 히스토그램 사용하지 않게하는 옵션 사용해서 삭제 시 발생하는 실행 계획 변경에 미리 대비는 가능 (특정 커넥션/쿼리 등 범위를 한정지어서 설정도 가능) - 히스토그램의 용도 - (before) 테이블과 인덱스에 대한 통계정보만으로 실행계획 수립 - (after) 테이블과 인덱스에 대한 통계정보 + 히스토그램의 분포도 정보 - (한 번 더 리마인드 > 히스토그램도 추정치임 특정 페이지만을 샘플링한 정보) - 실행 계획 정확도 up (405p 쿼리 참고) - 조인 순서 결정에 영향 -> 어느 테이블을 먼저 읽어야 조인 횟수를 줄일 수 있는지 정확한 판단 가능 (406p 쿼리 참고) - 히스토그램 & 인덱스 - 인덱스 다이브 - 실제 인덱스의 B-tree를 샘플링해서 본다 - 인덱스 다이브 통해 사용 가능한 인덱스들을 보고, 조건절에 일치하는 레코드 건수를 대략적으로 파악하는데 사용 - 인덱스 다이브는 언제 사용? - MySQL 8.0 서버부터는 인덱스된 컬럼을 검색 조건으로 사용하는 경우, 히스토그램이 아닌 인덱스 다이브를 활용 - 즉, 히스토그램은 인덱스되지 않은 칼럼에 대해서만 사용한다 - 인덱스 다이브의 단점? - 비용 - 특히 IN절이 늘어나면 실행 계획 수립만으로도 인덱스 다이브 실행 비용 크다 - (우디 추측) 인덱스 다이브는 그때그때 ~~만들어지나보다~~ 만들어지는 개념이 아니라 인덱스 몇 개만 샘플로 가져와 통계 자료로 활용하는 느낌 ### 10.1.3 코스트 모델(Cost Model) - 코스트 모델(Cost Model) : 전체 쿼리의 비용을 계산하는데 필요한 단위 작업들의 비용 - MySQL 5.7 버전까지는 - MySQL 서버 소스코드에 상수화 - 하드웨어 따라 달라질 수 있는 점은 고려 X - MySQL 5.7 이후부터는 - 각 단위 작업의 비용을 서버 밖에서 관리 (DB 관리자가 컨트롤 가능) - 409 페이지 참고, 코스트 모델의 어떤 단위 작업들에 대해서 비용 설정 가능한지 표기되어있음 - 작업 비용 높게 산정하면 그만큼 해당 단위 작업들에 쓰는 비용 증가 ## 10.2 실행 계획 확인 ### 10.2.1 실행 계획 출력 포맷 - MySQL 8.0 이후부터는, - 한 번의 EXPLAIN 명령으로 PARTITIONS, EXTEND 다 조회 가능 - PARTITIONS 과 EXTEND 옵션은 문법에서 안녕~ - FORMAT 옵션 - 실행 계획 표시 방법을 선택 가능 - JSON, TREE ### 10.2.2 쿼리의 실행 시간 확인 - `EXPLAIN ANALYZE` 기능 - 쿼리 실행 계획 확인 - 실행 단계별로 소요된 시간 정보 확인 가능 - `EXPLAIN`과 다르다 : `EXPLAIN ANALYZE`는 실제 쿼리를 실행하고 사용된 실행계획과 소요된 시간을 보여줌 - 실행 순서 기준 - 들여쓰기가 같은 레벨 -> 상단에 위치한 라인 먼저 - 들여쓰기 다른 레벨 -> 가장 안쪽 라인 먼저 - `EXPLAIN ANALYZE` 요소 ([공식 문서 참고](https://dev.mysql.com/blog-archive/mysql-explain-analyze/#:~:text=What%20is%20it%3F,points%20in%20the%20execution%20plan.)) - actual time : {첫 번째 레코드 검색하는데 걸린 시간}...{마지막 레코드 검색하는데 걸린 시간} - rows : 처리한(읽은) 레코드 갯수 - loops : 작업이 반복된 횟수 - 414p 예시 함께 잠깐 보기 - (우디 자문자답) 왜 F가 가장 먼저 실행되는게 아닐까 - F 구문이 D에 종속적이라서 그런 듯하다 ## 10.3 실행 계획 분석 - focus on - 실행 계획이 어떤 접근 방법을 사용해서 어떤 최적화 수행하는지 - 어떤 인덱스 사용하는지 - EXPLAIN 테이블 - 표의 각 라인(레코드) - 쿼리 문장에서 사용된 테이블 (+ 임시테이블도 포함) 출력 - 실행 순서대로 출력 (UNION, 상관 서브 쿼리 제외) - (+ 상관 서브쿼리 : 내부 쿼리의 값이 결정되는데 외부 쿼리에 의존하는 쿼리) - 위일 수록 outer 혹은 먼저 접근한 테이블, 아래쪽일 수록 inner 혹은 나중에 접근한 테이블 ### 10.3.1 id 칼럼 - 단위 SELECT 쿼리별로 부여되는 식별자 - (+ 단위 쿼리 = SELECT 키워드 단위로 구분한 쿼리) - 여러 개의 레코드가 같은 id 가질 수 있다 - 하나의 SELECT 문장 내 여러 개의 테이블을 조인하면, 조인되는 테이블 개수만큼 실행 계획 레코드가 출력, BUT 같은 id 값 가짐 - id 칼럼 != 테이블 접근 순서 ### 10.3.2 select_type 칼럼 - 단위 SELECT 쿼리가 어떤 타입의 쿼리인지 표시됨 #### Simple - UNION이나 서브 쿼리 사용하지 않는 단순 SELECT 쿼리 - 일반적, 가장 바깥 SELECT 쿼리 #### Primary - UNION이나 서브 쿼리 사용하는 SELECT 쿼리의 실행계획에서 가장 Outer 단위 쿼리 #### Union - UNION으로 결합하는 단위 SELECT 쿼리 중 - 첫 번째 : DERIVED - 첫 번째 이후 단위 쿼리 : UNION - (우디) Union 키워드 사용 시, 내부적으로는 임시 테이블 사용하는 구나 #### Dependent Union - 집합을 결합하는 단위 쿼리(UNION, UNION ALL)에서 외부 쿼리에 의해 영향을 받을 경우 - 상관 서브쿼리일 경우, DEPENDENT 키워드 표시 #### Union Result - UNION의 결과를 담아두는 임시 테이블 - 단위 쿼리가 아니므로 별도 id 값은 X - <union 1, 2> : id 값 1와 2 단위쿼리 결과를 조합 - MySQL 8.0 이전 : UNION ALL 혹은 UNION 쿼리는 결합 결과를 모두 임시 테이블로 생성 - MySQL 8.0 이후 : UNION ALL 사용하지 않도록 변경됨 / UNION 여전히 임시 테이블 생성 #### Subquery > - 위치에 따른 서브 쿼리 명 > - 중첩된 쿼리 : SELECT 절 > - 서브쿼리 : WHERE 절 > - 파생 테이블 : FROM 절 (= 인라인뷰 = 서브 셀렉트) > - 반환 값 개수 > - 스칼라 서브쿼리 : 컬럼 하나인 레코드 1건의 값 1개만 반환 > - 로우 서브쿼리 : 컬럼 개수와 상관없이 하나의 레코드만 반환 - 여기서의 SUBQUERY는 FROM절 이외에서 사용되는 서브쿼리만을 말한다 - (FROM절에서 사용되는 서브쿼리 = DREIVED 표시) #### Dependent Subquery - 서브쿼리가 Outer SELECT 쿼리에서 정의된 칼럼을 사용하는 경우 - 일반적인 서브쿼리보다 처리속도 느리다 - 외부 쿼리 먼저 수행된 후 내부 쿼리 실행되어야 하므로 #### Derived - MySQL 5.6 이전 - 서브쿼리 FROM 절 -> 임시 테이블 만든다 -> DERIVED 실행 계획 - MySQL 5.6 이후 - FROM 절의 서브쿼리를 외부 쿼리와 통합하는 식의 최적화로 인해 반드시 DERIVED 실행 계획인건 아니게 됨 - 임시 테이블에서도 인덱스 추가해서 만들 수 있게 됨 (옵티마이저 옵션별로 상이) - (우디) 서브쿼리 있으면 최대한 조인으로 풀어보자고 또 한 번 다짐.. #### Dependent Derived - FROM 절 서브쿼리에서 외부 칼럼 사용할 경우 - MySQL 8.0 이전 - FROM 절 서브쿼리에서 외부 칼럼 사용 X - MySQL 8.0 이후 - lateral join을 사용하면 가능 - [lateral join 설명 링크](https://stackoverflow.com/a/28551339) - Q : one to many -> many 제한 #### Uncacheable Subquery - 캐시를 사용할 수 없는 서브쿼리를 사용하는 경우 - 원래는 이전의 실행 결과를 그대로 사용할 수 있도록 서브 쿼리 결과를 내부 캐시에 저장 - 서브쿼리 캐시 != 쿼리 캐시 혹은 파생 테이블 - 캐시 사용 방법 - SUBQUERY : 한 번 실행에 대한 결과를 캐시하고, 필요할 때 사용 - DEPENDENT SUBQUERY : 의존하는 바깥 쿼리의 칼럼 값 단위로 캐시해둔다 (?? 정확한 과정은 잘 모르겠어욥) - 캐시 사용하지 못하게 하는 요소들 3가지 (428p) #### Uncacheable Union - 캐시를 사용할 수 없는 유니언 쿼리 사용하는 경우 #### Materialized - MySQL 5.7 이전 - outer 테이블 레코드마다 서브 쿼리 실행 - MySQL 5.7 이후 - FROM절 혹은 IN(subquery) 형태의 쿼리에 대해서, 서브쿼리 내용을 임시 테이블로 구체화한 뒤 outer 테이블과 조인하는 형태로 최적화 - Derived 와 동일하게 작동, 서브쿼리의 위치가 다른 것일 뿐임 ### 10.3.3 table 칼럼 - MySQL 서버의 실행 계획은 테이블 기준 - <> 표시는 임시 테이블을 의미, 안의 숫자는 단위 SELECT 쿼리 id 값을 지칭 ### 10.3.4 partitions 칼럼 - MySQL 8.0 버전부터는 EXPLAIN 명령으로 파티션 관련 실행 계획까지 한 번에 확인 가능 - 파티션 프루닝 : 파티션이 여러 개인 테이블에서 불필요한 파티션을 빼고 쿼리를 수행하도록, 테이블을 골라내는 과정 - 옵티마이저에서는 쿼리의 조건들을 확인하고, 필요한 파티션만 접근하는 파티션 프루닝으로 쿼리 최적화 시도 - (+) 대부분 RDB에서 지원하는 파티션은 물리적으로 별도의 공간을 가진다 (그러니, 실행 계획 상으로는 type ALL로 뜰 수 있으니 놀라지 말 것. 우리들이 생각하는 풀스캔 타는거 아님) ### 10.3.5 type 칼럼 - 인덱스를 효율적으로 사용하는지 확인할 수 있는 컬럼 - type 컬럼 == 조인 타입... 이라고 되어있지만 '각 테이블의 접근 방법'이라고 생각해도 좋음 #### system - 레코드가 1건 혹은 아예 존재하지 않는 테이블 참조 - MyISAM 혹은 MEMORY 테이블에서만 사용 #### const - 프라이머리 키 혹은 유니크 키 칼럼을 이용하는 WHERE 조건절을 가지고 있고 + 반드시 1건을 반환하는 쿼리만을 처리 - 유니크 인덱스 스캔이라고도 함 - 일부 칼럼만 조건을 사용할 때는 X -> const가 아닌 ref - 옵티마이저의 쿼리 최적화 단계에서 const인 실행 계획은 먼저 쿼리를 실행해서 통째로 상수화한다 (우디 : 그래서 반드시 1건을 반환해야하는군!) #### eq_ref - 여러 테이블이 조인되는 쿼리 실행 계획에서만 표시 - 첫 번째 테이블 컬럼값을 두 번째 조인되는 테이블의 PK 혹은 유니크 키 컬럼의 검색조건(조인 조건)으로 사용할 때 - 두 번재 조인 테이블의 type 컬럼 eq_ref - 유니크 키로 검색할 경우 NOT NULL이어야 함 - 조인에서 두 번째 이후에 읽는 테이블에서 반드시 1건만 존재한다는 보장이 있어야 함 #### ref - 조인의 순서와 관계 없이 사용 + PK 혹은 유니크 키 제약 조건도 X - 반드시 1건이라는 보장이 없음 (eq_ref가 더 빠름) - 동등 조건으로만 비교하기 때문에 여전히 빠름 > const, eq_ref, ref > - 동등 비교 연산자 사용 > - 쿼리 튜닝시 나오면 좋은 type #### fulltext - MySQL 서버의 전문 검색 인덱스를 사용해 레코드를 읽는 접근 방식 - 전문 검색 인덱스는 통계정보 관리 X - `MATCH (..) AGANIST (..)` 구문으로 전문 검색 실행 #### ref_or_null - ref 접근 방법 + null 비교 추가 - 나쁘지는 않다 (ㅋㅋ) #### unique_subquery - Where 조건절에서 사용되는 IN(서브 쿼리)를 위한 접근 방식 - 서브쿼리에서 중복되지 않는 유니크한 값만 반환할 때 #### index_subquery - IN(서브 쿼리) 결과에서 중복된 값이 발생했을 때, 인덱스로 중복된 값을 제거할 수 있음 #### range - 인덱스 레인지 스캔 형태의 접근 방법 - 범위 형태로 검색하는 경우 적용 (< >, is null, between, in, like) > 인덱스를 효율적으로 사용한다 > - const, ref, range 사용한다 > (우디 질문 : const는 왜 레인지 스캔일까) #### index_merge - 2개 이상의 인덱스를 이용 -> 검색 결과 각각 만듦 -> 병합 - (-) 여러 인덱스 읽어야 함 - (-) 전문 검색 인덱스 사용 쿼리는 적용 안됨 - (-) 검색 결과를 모아주는 비용이 필요 (교집합, 합집합, 중복제거 등등) #### index - 인덱스 풀 스캔 - 비교 레코드 건수는 테이블 풀 스캔과 동일, BUT 데이터 파일 크기가 다름 #### ALL - 풀 테이블 스캔 - 가장 비효율적인 방법 - '쿼리 튜닝을 한다'는 것이 반드시 인덱스 혹은 테이블 풀 스캔을 사용하지 못하게 하는건 아님 - 배치 프로그램으로 데이터를 일괄 읽어들여야 하는 상황이나, ### 10.3.6 possible_keys 칼럼 ### 10.3.7 key 칼럼 ### 10.3.8 key_len 칼럼 ### 10.3.9 ref 칼럼 ### 10.3.10 rows 칼럼 ### 10.3.11 filtered 칼럼

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully