sql 문장을 최적화하는 일반 절차

14400 단어 mysql
1. show status 명령을 통해 각종 sql의 실행을 파악 mysql 클라이언트 연결이 성공하면 show [session|global]status 명령을 통해 서버 상태 정보를 제공할 수도 있고 운영체제에서 mysqladmin extend-status 명령을 사용하여 이 정보를 얻을 수도 있습니다.show status 명령 중간에 옵션session(기본값) 또는 글로벌을 추가할 수 있습니다.
  • session(현재 연결)
  • 글로벌(데이터가 지난번에 시작된 이후)
  • # Com_xxx      xxx        。
    mysql> show status like 'Com_%';

    우리가 일반적으로 관심을 가지는 것은 다음과 같은 몇 가지 통계 매개 변수이다.
  • Com_select: select 조작을 실행하는 횟수입니다. 한 번의 조회는 1만 누적됩니다.
  • Com_insert: insert 동작을 실행하는 횟수입니다. 대량으로 삽입된 insert 동작은 한 번만 누적됩니다.
  • Com_업데이트: 업데이트 작업을 실행하는 횟수입니다.
  • Com_delete: delete 작업을 수행한 횟수입니다.

  • 위의 매개 변수는 모든 메모리 엔진의 테이블 작업에 누적됩니다.아래의 몇 개의 매개 변수는 innodb에 대한 것일 뿐 누적된 알고리즘도 약간 다르다.
  • Innodb_rows_read:select 조회가 되돌아오는 줄 수입니다.
  • Innodb_rows_inserted: insert 동작을 실행하여 삽입한 줄 수입니다.
  • Innodb_rows_업데이트: 업데이트 작업을 실행하는 줄 수입니다.
  • Innodb_rows_deleted: delete 작업을 실행하여 삭제한 줄 수입니다.

  • 상기 몇 가지 파라미터를 통해 현재 데이터베이스의 응용이 삽입 업데이트를 위주로 하는지 조회 조작을 위주로 하는지 각종 유형의 sql의 대체적인 집행 비례가 얼마나 되는지 쉽게 알 수 있다.업데이트 작업의 개수는 실행 횟수에 대한 개수입니다. 제출이든 스크롤이든 누적됩니다.트랜잭션 응용의 경우 Comcommit 및 Comrollback은 업무 제출과 스크롤의 상황을 이해할 수 있으며 스크롤 작업이 매우 빈번한 데이터베이스에 대해 응용 프로그램 작성에 문제가 있음을 의미할 수 있다.또한 다음과 같은 몇 가지 매개변수를 사용하여 데이터베이스의 기본 상태를 쉽게 이해할 수 있습니다.
  • Connections: mysql 서버에 연결하려는 횟수입니다.
  • Uptime: 서버 작업 시간.
  • Slow_queries: 느린 조회 횟수입니다.

  • 2. 실행 효율이 낮은 sql 문장을 정의한다
    1. 느린 조회 로그를 통해 실행 효율이 낮은 sql 문장을 포지셔닝하고 --log-slow-queries [=file name] 옵션으로 시작할 때 mysqld는 모든 실행 시간을 포함하여longquery_time초의 sql 문장의 로그 파일입니다.
    2. 느린 조회 로그는 조회가 끝난 후에야 기록되기 때문에 응용 프로그램이 실행 효율에 문제가 발생했을 때 느린 조회 로그는 문제를 포지셔닝할 수 없습니다. showprocesslist 명령을 사용하여 현재 mysql가 진행하고 있는 라인을 볼 수 있습니다. 라인의 상태, 자물쇠 테이블 여부 등을 포함하여 sql의 실행 상황을 실시간으로 볼 수 있고 일부 자물쇠 테이블 조작을 최적화할 수 있습니다.
    3. explain을 통해 저효율 sql의 실행 계획을 분석
    테스트 데이터베이스 주소:https://downloads.mysql.com/d...
    어떤 이메일이 영화 복사본을 임대하기 위해 지불한 총 금액을 통계하려면 고객표customer와 지불표payment와 관련되고 지불금액amount 필드에 대해 화합(sum) 조작을 해야 한다. 상응하는 집행 계획은 다음과 같다.
    mysql> explain select sum(amount) from customer a , payment b where a.customer_id= b.customer_id and a.email='[email protected]'\G  
    
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: a
       partitions: NULL
             type: ALL
    possible_keys: PRIMARY
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 599
         filtered: 10.00
            Extra: Using where
    *************************** 2. row ***************************
               id: 1
      select_type: SIMPLE
            table: b
       partitions: NULL
             type: ref
    possible_keys: idx_fk_customer_id
              key: idx_fk_customer_id
          key_len: 2
              ref: sakila.a.customer_id
             rows: 26
         filtered: 100.00
            Extra: NULL
    2 rows in set, 1 warning (0.00 sec)
    
  • select_type: select 유형을 나타내며 일반적인 값은 다음과 같습니다.
  • 단순: 간단한 테이블 및 테이블 연결 또는 하위 조회를 사용하지 않음
  • primary: 메인 쿼리, 즉 외부 쿼리
  • union:union의 두 번째 또는 뒤에 있는 검색어구
  • subquery: 하위 검색의 첫 번째 select
  • table: 출력 결과 집합의 표
  • type: mysql가 테이블에서 필요한 줄을 찾거나 접근 유형을 나타낸다. 흔히 볼 수 있는 유형의 성능은 다음과 같다. all, index,range,ref,eqref、const,system、null:
  • type=ALL, 전체 테이블 스캔, mysql 전체 테이블을 옮겨다니며 일치하는 줄을 찾습니다:
    mysql> explain select * from film where rating > 9 \G
    
    *************************** 1. row ***************************
              id: 1
     select_type: SIMPLE
           table: film
      partitions: NULL
            type: ALL
    possible_keys: NULL
             key: NULL
         key_len: NULL
             ref: NULL
            rows: 1000
        filtered: 33.33
           Extra: Using where
    1 row in set, 1 warning (0.01 sec)
    
  • type=index, 인덱스 전체 스캔, mysql 전체 인덱스를 옮겨다니며 일치하는 줄 조회
    mysql> explain select title form film\G
    
    *************************** 1. row ***************************
              id: 1
     select_type: SIMPLE
           table: film
      partitions: NULL
            type: index
    possible_keys: NULL
             key: idx_title
         key_len: 767
             ref: NULL
            rows: 1000
        filtered: 100.00
           Extra: Using index
    1 row in set, 1 warning (0.00 sec)
    
  • type=range, 색인 범위 스캔, 흔한, >=,between 등 조작:
    mysql> explain select * from payment where customer_id >= 300 and customer_id <= 350 \G  
    
    *************************** 1. row ***************************
              id: 1
     select_type: SIMPLE
           table: payment
      partitions: NULL
            type: range
    possible_keys: idx_fk_customer_id
             key: idx_fk_customer_id
         key_len: 2
             ref: NULL
            rows: 1350
        filtered: 100.00
           Extra: Using index condition
    1 row in set, 1 warning (0.07 sec)
    
  • type=ref, 유일한 인덱스 스캔이나 유일한 인덱스가 아닌 접두사 스캔을 사용하여 특정한 단독 값과 일치하는 기록 줄을 되돌려줍니다. 예를 들어
    mysql> explain select * from payment where customer_id = 350 \G  
    *************************** 1. row ***************************
              id: 1
     select_type: SIMPLE
           table: payment
      partitions: NULL
            type: ref
    possible_keys: idx_fk_customer_id
             key: idx_fk_customer_id
         key_len: 2
             ref: const
            rows: 23
        filtered: 100.00
           Extra: NULL
    1 row in set, 1 warning (0.01 sec)
    
    인덱스 idxfk_customer_id는 유일한 인덱스가 아닙니다. 검색 조건은 등가 검색 조건customerid = 350이기 때문에 색인을 스캔하는 형식은ref입니다.ref는join 작업에 자주 나타난다.
    mysql> explain select b.*, a.* from payment a,customer b where a.customer_id = b.customer_id \G 
    
    *************************** 1. row ***************************
              id: 1
     select_type: SIMPLE
           table: b
      partitions: NULL
            type: ALL
    possible_keys: PRIMARY
             key: NULL
         key_len: NULL
             ref: NULL
            rows: 599
        filtered: 100.00
           Extra: NULL
    *************************** 2. row ***************************
              id: 1
     select_type: SIMPLE
           table: a
      partitions: NULL
            type: ref
    possible_keys: idx_fk_customer_id
             key: idx_fk_customer_id
         key_len: 2
             ref: sakila.b.customer_id
            rows: 26
        filtered: 100.00
           Extra: NULL
    2 rows in set, 1 warning (0.00 sec)
    
  • type=eq_ref, 유사한ref, 구별은 사용하는 인덱스에서 유일한 인덱스이며, 모든 인덱스의 키 값에 대해 표에 기록이 일치하기만 하면 된다.간단하게 말하면 다중 테이블 연결에서primary 키나 unique index를 관련 조건으로 사용한다.
    mysql> explain select * from film a , film_text b where a.film_id = b.film_id \G
    
    *************************** 1. row ***************************
              id: 1
     select_type: SIMPLE
           table: b
      partitions: NULL
            type: ALL
    possible_keys: PRIMARY
             key: NULL
         key_len: NULL
             ref: NULL
            rows: 1000
        filtered: 100.00
           Extra: NULL
    *************************** 2. row ***************************
              id: 1
     select_type: SIMPLE
           table: a
      partitions: NULL
            type: eq_ref
    possible_keys: PRIMARY
             key: PRIMARY
         key_len: 2
             ref: sakila.b.film_id
            rows: 1
        filtered: 100.00
           Extra: Using where
    2 rows in set, 1 warning (0.03 sec)
    
  • type=const/system, 한 표에 가장 많은 일치하는 줄이 있는데, 검색이 매우 빠르기 때문에 이 일치하는 줄의 다른 열의 값은 최적화기가 현재 검색에서 상수로 처리할 수 있습니다. 예를 들어 메인 키primary 키나 유일한 인덱스unique index에 따라 검색할 수 있습니다.
    mysql> create table test_const (
       ->         test_id int,
       ->         test_context varchar(10),
       ->         primary key (`test_id`),
       ->     );
       
    insert into test_const values(1,'hello');
    
    explain select * from ( select * from test_const where test_id=1 ) a \G
    *************************** 1. row ***************************
              id: 1
     select_type: SIMPLE
           table: test_const
      partitions: NULL
            type: const
    possible_keys: PRIMARY
             key: PRIMARY
         key_len: 4
             ref: const
            rows: 1
        filtered: 100.00
           Extra: NULL
     1 row in set, 1 warning (0.00 sec)
  • type=null, mysql은 테이블이나 인덱스에 접근하지 않고 바로 결과를 얻을 수 있습니다.
    mysql> explain select 1 from dual where 1 \G
    *************************** 1. row ***************************
              id: 1
     select_type: SIMPLE
           table: NULL
      partitions: NULL
            type: NULL
    possible_keys: NULL
             key: NULL
         key_len: NULL
             ref: NULL
            rows: NULL
        filtered: NULL
           Extra: No tables used
    1 row in set, 1 warning (0.00 sec)
    
  • 유형 type에는 ref 와 같은 다른 값도 있습니다.or_null(ref와 유사하며 조건에 null에 대한 조회가 포함된 것과 다르다), indexmerge(인덱스 통합 최적화), uniquesubquery (in 뒤에는 쿼리 키 필드의 하위 쿼리), indexsubquery (unique subquery와 유사하며 in의 뒤에는 유일한 인덱스 필드가 아닌 하위 쿼리가 있음) 등이 있습니다.
  • possible_keys: 검색할 때 사용할 수 있는 색인을 표시합니다.
  • key: 실제 사용 색인을 표시
  • key-len: 색인 필드의 길이를 사용합니다.
  • rows: 스캔 줄의 수량
  • extra: 실행 상황에 대한 설명과 설명은 다른 열에 표시하기에는 적합하지 않지만 실행 계획에 대한 중요한 추가 정보를 포함합니다.

  • show warnings 명령
    explain을 실행한 후에 show warnings를 실행하면 sql가 실제로 실행되기 전에 최적화기가 어떤 sql 컴파일러를 했는지 볼 수 있습니다.
    MySQL [sakila]> explain select sum(amount) from customer a , payment b where 1=1 and a.customer_id = b.customer_id and email = '[email protected]'\G
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: a
       partitions: NULL
             type: ALL
    possible_keys: PRIMARY
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 599
         filtered: 10.00
            Extra: Using where
    *************************** 2. row ***************************
               id: 1
      select_type: SIMPLE
            table: b
       partitions: NULL
             type: ref
    possible_keys: idx_fk_customer_id
              key: idx_fk_customer_id
          key_len: 2
              ref: sakila.a.customer_id
             rows: 26
         filtered: 100.00
            Extra: NULL
    2 rows in set, 1 warning (0.00 sec)
    
    MySQL [sakila]> show warnings;
    +-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Level | Code | Message                                                                                                                                                                                                                                                     |
    +-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Note  | 1003 | /* select#1 */ select sum(`sakila`.`b`.`amount`) AS `sum(amount)` from `sakila`.`customer` `a` join `sakila`.`payment` `b` where ((`sakila`.`b`.`customer_id` = `sakila`.`a`.`customer_id`) and (`sakila`.`a`.`email` = '[email protected]')) |
    +-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    1 row in set (0.00 sec)
    

    Warning의 메시지 필드에서 최적화기가 1=1항성립 조건을 자동으로 제거하는 것을 볼 수 있다. 즉, 최적화기가 sql를 고칠 때 항성립 조건을 자동으로 제거한다.
    explain 명령도 구역에 대한 지원이 있습니다.
    MySQL [sakila]> CREATE TABLE `customer_part` (
        ->   `customer_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
        ->   `store_id` tinyint(3) unsigned NOT NULL,
        ->   `first_name` varchar(45) NOT NULL,
        ->   `last_name` varchar(45) NOT NULL,
        ->   `email` varchar(50) DEFAULT NULL,
        ->   `address_id` smallint(5) unsigned NOT NULL,
        ->   `active` tinyint(1) NOT NULL DEFAULT '1',
        ->   `create_date` datetime NOT NULL,
        ->   `last_update` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        ->   PRIMARY KEY (`customer_id`)
        ->  
        -> ) partition by hash (customer_id) partitions 8;
    Query OK, 0 rows affected (0.06 sec)
    
    MySQL [sakila]> insert into customer_part select * from customer;
    Query OK, 599 rows affected (0.06 sec)
    Records: 599  Duplicates: 0  Warnings: 0
    
    MySQL [sakila]> explain select * from customer_part where customer_id=130\G
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: customer_part
       partitions: p2
             type: const
    possible_keys: PRIMARY
              key: PRIMARY
          key_len: 2
              ref: const
             rows: 1
         filtered: 100.00
            Extra: NULL
    1 row in set, 1 warnings (0.00 sec)
    

    sql가 접근하는 구역은 p2입니다.
    4.performance를 통해schema 분석 sql 성능
    구 버전의 mysql는profiles를 사용하여 sql의 성능을 분석할 수 있습니다. 저는 5.7.18버전을 사용했습니다. 프로필을 사용할 수 없습니다.performanceschema 분석 sql.
    5.trace분석을 통해 최적화기가 어떻게 실행 계획을 선택하는지 분석한다.
    mysql5.6 sql에 대한 추적trace를 제공하여 왜 최적화기가 B 실행 계획이 아닌 A 실행 계획을 선택했는지 이해할 수 있고 최적화기의 행위를 더욱 잘 이해할 수 있다.
    사용 방식: 우선trace를 열고 형식을 json으로 설정하고trace가 사용할 수 있는 최대 메모리 크기를 설정하여 해석 과정에서 기본 메모리가 너무 작아서 완전하게 보이지 않도록 합니다.
    MySQL [sakila]> set optimizer_trace="enabled=on",end_markers_in_json=on;
    Query OK, 0 rows affected (0.00 sec)
    
    MySQL [sakila]> set optimizer_trace_max_mem_size=1000000;
    Query OK, 0 rows affected (0.00 sec)
    

    다음은trace를 하고 싶은 sql 문장을 실행합니다. 예를 들어 임대표rental의 재고 번호 inventory 를 알아보는 것과 같습니다.id 4466 영화 카피 대여 날짜rentaldate는 2005-05-25 4:00:00 ~ 5:00:00 사이의 임대 기록:
    mysql> select rental_id from rental where 1=1 and rental_date >= '2005-05-25 04:00:00' and rental_date <= '2005-05-25 05:00:00' and inventory_id=4466;
    +-----------+
    | rental_id |
    +-----------+
    |        39 |
    +-----------+
    1 row in set (0.06 sec)
    
    MySQL [sakila]> select * from information_schema.optimizer_trace\G
    *************************** 1. row ***************************
                                QUERY: select * from infomation_schema.optimizer_trace
                                TRACE: {
      "steps": [
      ] /* steps */
    }
    MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0
              INSUFFICIENT_PRIVILEGES: 0
    1 row in set (0.00 sec)
    

    6. 문제를 확정하고 해당하는 최적화 조치를 취한다.
    이상의 절차를 거치면 기본적으로 문제가 발생한 원인을 확인할 수 있다.이때 상황에 따라 상응하는 조치를 취하여 집행의 효율을 높일 수 있다.

    좋은 웹페이지 즐겨찾기