sql 문장을 최적화하는 일반 절차
14400 단어 mysql
mysql 클라이언트 연결이 성공하면 show [session|global]status 명령을 통해 서버 상태 정보를 제공할 수도 있고 운영체제에서 mysqladmin extend-status 명령을 사용하여 이 정보를 얻을 수도 있습니다.show status 명령 중간에 옵션session(기본값) 또는 글로벌을 추가할 수 있습니다.# Com_xxx xxx 。
mysql> show status like 'Com_%';
우리가 일반적으로 관심을 가지는 것은 다음과 같은 몇 가지 통계 매개 변수이다.
위의 매개 변수는 모든 메모리 엔진의 테이블 작업에 누적됩니다.아래의 몇 개의 매개 변수는 innodb에 대한 것일 뿐 누적된 알고리즘도 약간 다르다.
상기 몇 가지 파라미터를 통해 현재 데이터베이스의 응용이 삽입 업데이트를 위주로 하는지 조회 조작을 위주로 하는지 각종 유형의 sql의 대체적인 집행 비례가 얼마나 되는지 쉽게 알 수 있다.업데이트 작업의 개수는 실행 횟수에 대한 개수입니다. 제출이든 스크롤이든 누적됩니다.트랜잭션 응용의 경우 Comcommit 및 Comrollback은 업무 제출과 스크롤의 상황을 이해할 수 있으며 스크롤 작업이 매우 빈번한 데이터베이스에 대해 응용 프로그램 작성에 문제가 있음을 의미할 수 있다.또한 다음과 같은 몇 가지 매개변수를 사용하여 데이터베이스의 기본 상태를 쉽게 이해할 수 있습니다.
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)
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)
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)
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)
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)
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)
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)
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)
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. 문제를 확정하고 해당하는 최적화 조치를 취한다.
이상의 절차를 거치면 기본적으로 문제가 발생한 원인을 확인할 수 있다.이때 상황에 따라 상응하는 조치를 취하여 집행의 효율을 높일 수 있다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
MySQL에서 JSON 인덱싱 - aarondfrancis사람들은 종종 MySQL로 JSON을 인덱싱할 수 없다고 말하지만 완전히 정확하지는 않습니다. MySQL로 JSON 열을 인덱싱하는 것은 완전히 가능합니다! 사람들은 종종 MySQL로 JSON을 인덱싱할 수 없다고 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.