온라인 SQL 인덱스 최적화 및 인덱스 선택 오류의 원리 분석

내 동료가 이틀 전 담당 한 주문 모듈의 질의에서 이상한 문제가 발생했습니다. 필터 조건이 추가되면 질의 시간 초과 문제가 발생합니다. 모든 주문을 질의 할 때 문제가 없습니다. SQL은 다음과 같습니다 (데이터가 둔화되어 MySql 사용).

SELECT
	a.consumer_code AS orderCode,
	a.rent_equipment_snid AS eqSn,
	a.powerbank_snid AS pbSn,
	a.rent_merchant_name AS rentMerchant,
	a.rent_merchant_address AS merchantAddress,
	a.rent_date AS rentTime,
	a.close_date AS returnTime,
	a.payment_money AS orderAmount,
	a.order_status AS orderStatus,
	a.consume_schema AS consumeSchema,
	a.transaction_status AS transStatus,
	a.rent_equipment_model AS eqModel 
FROM
	cp_consumer_order_2020_10 a 
WHERE
	a.agent_code = xxxx
	# 下面两个条件就是筛选时才会加上
	AND a.order_status = xxx 
	AND a.close_date IS NULL 
ORDER BY
	a.consumer_code desc

cp_consumer_order_2020_10은 월별 주문 테이블로 거의 천만 개의 데이터가 있고 consumer_code는 기본 키이며 agent_code는 일반 인덱스가 있습니다.
위의 SQL을 데이터베이스에서 실행 한 결과 agent_code 인덱스가 사라지고 쿼리 효율이 정상인 것을 확인한 후 필터 조건을 삭제했는데 실행 결과는 동일했습니다.여기에 사진 설명 삽입
여기에 사진 설명 삽입

위는 조건부와 무조건 실행 계획으로 차이가 없음을 알 수 있습니다. 이때
여기에 사진 설명 삽입
코드 에 시간이 많이 걸리는 작업이 있는지 궁금합니다. 이 코드에는 특별히 시간이 많이 걸리는 작업이없는 것 같습니다. getAgentOrderList는 해당 SQL을 실행하고 getAgentStaffOrderList도 페이징으로 인해 매우 빠르게 쿼리를 시도했습니다. 루프 실행은 특별히 느리지 않습니다.
또 다른 "영적 사건"이 발생했을 가능성이 있습니까? 이때 갑자기 페이징에 의한 것일까 생각했는데, 오프셋이 너무 크면 리미트가 느려질 것이라는 것을 모두 알고 있지만 아직 첫 페이지 인 페이지를 넘기지 않았기 때문에 문제가되지 않습니다.
또한 이전에 limit와 order by를 사용할 때 인덱스 선택 오류 문제를 본 적이 있다고 생각하여 제한 0,30을 가져 와서 바로 지금 데이터베이스에서 SQL을 실행했는데 예상대로 느린 SQL이 나타났습니다. 이때 실행 계획을 다음과 같이 살펴 보겠습니다.
여기에 사진 설명 삽입
Mysql이 현재 기본 키 인덱스, 즉 우리가 정렬 한 필드를 사용하는 것을 볼 수 있으므로 동료 인덱스를 사용하여 강제 인덱스를 사용하여 일반 인덱스를 강제 실행하면 쿼리가 정상으로 돌아갑니다.
이 시점에서 SQL 최적화는 끝났지 만 제한을 추가하면 Mysql이 잘못된 인덱스를 선택하는 이유는 무엇이며 기본 키 인덱스를 사용하는 것이 느린 이유는 무엇이며 스캔 된 행의 예상 수는 분명히 적습니까? "무슨 일이 일어나고 있는지 알면서도 이유를 안다"라는 원칙에 따라 많은 정보를 확인했지만 마음 속의 의심을 완전히 풀 수 없었고, 결국 반복해서 시도하고 마침내 얻었습니다.

  • 우선 일반 인덱스를 사용하는 것이 더 빠르지 만 기본 키 인덱스가 느린 이유는 무엇입니까?
    내 SQL은 기본 키 인덱스를 역순으로 쿼리 한 결과이기 때문에 인덱스는 자연스럽게 정렬되고 정렬 할 필요가 없습니다. 따라서 실행 계획의 Extra 필드에는 일반 인덱스보다 빠른 Using filesort가 없지만이 SQL은 where 조건에 따라 필터링됩니다. 예, 정렬 된 결과를 얻은 후 agent_code와 where 조건을 하나씩 가져 와서 일치시켜야합니다. 이것을 보면 독자가 기본적으로 이해해야한다고 생각합니다. 한계가 없으면이 SQL은 전체 테이블 스캔을하고 한계가 0,30이면 다음과 같은 상황이 발생합니다 : 첫째, where 조건에 맞는 30 개의 레코드가 딱 맞습니다. 정렬 후 처음 30 개 항목이면 mysql은 30 개 항목 만 스캔하면됩니다 .30 개 미만의 항목이 있거나 정렬이 끝날 때 일치하는 레코드가 있으면 전체 테이블을 스캔합니다. 그러나 일반 인덱스 agent_code는 필터 조건이 agent_code이므로 신속하게 일치시킬 수 있으므로 이러한 문제가 없습니다.
  • 제한이 추가 될 때 기본 키 인덱스가 사용되는 이유는 무엇입니까?
    기본 키 인덱스를 제한없이 사용하면 위에서 언급 한대로 where 조건에 하나씩 일치하지만 반환되는 항목 수에는 제한이 없으며 전체 테이블 스캔이 수행됩니다 (force index (primary) + explain을 사용하여 행을 볼 수 있습니다. 테이블의 총 행 수 (1000w)이며, Mysql은 일반 인덱스에 대한 스캔 행의 예상 개수가 1.8W 미만이기 때문에 일반 인덱스를 사용하는 것이 더 빠르다고 생각합니다. 그러나 제한을 추가 한 후 기본 키 인덱스에 대한 예상 스캔 행 수는 다음과 같을 수 있습니다. 일반 인덱스의 예상 스캔 라인 수보다 적기 때문에 인덱스 선택 오류가 발생합니다.

추천

출처blog.csdn.net/l6108003/article/details/109382533