今天檢查滿查詢日志發現有個存儲過程查詢可以達17S
而且是訂單列表查詢,這個當然不能忍了,必須優化,接下來就是查找原因優化過程。過程使用動態語句,首先使用滿查詢的語句條件提取出來靜態語句單獨分析:
提取結果如下:
table1 表數據100W+ table3表數據200W+
SELECT b.*, A.value1, A.value2, A.value3, A.value4, A.value5, A.value6, FROM table1 b LEFT JOIN table2A ON b.order_no = A.order_no AND b.channel_no = A.channel_no WHERE 1 = 1 AND EXISTS (SELECT 1 FROM table3 t WHERE b.order_no = t.order_no AND t.ticket_no LIKE '%1792903240%') ORDER BY CREATE_TIME LIMIT 0, 20
為什么這個過程要10s+ 呢?
主要原因在於 exists這個部分,因為 table3有200W的數據,並且循環式和外表掃描查詢,並且這里的like是不會走索引的,只能全掃描,所以慢就很明顯了,由於是動態語句,並在存儲過程中,所以優化就是拆解EXISTS這部分
主要思路就是 先從200W+ 的table3中查出來order_no 然后把order_no插入臨時表,然后再使用in 臨時表查詢,減少關聯掃描次數就能極大的優化查詢時間
前提: table3中的ticket_no 重復率非常低,200W+的數據 有200W的非重復,為什么強調這個,臨時表在處理少量數據時性能很優異,(一般只在確定不能用索引的時候才使用臨時表,或者在存儲過程中某些固定數據使用次數非常多的時候使用臨時表,其他時候我一般不建議使用)
優化結果:
CREATE TEMPORARY TABLE tmp_order_no (ticket_order_no varchar(100)); INSERT INTO tmp_order_no SELECT tp.order_no FROM t_passenger tp WHERE tp.ticket_no LIKE CONCAT('%',2903240,'%'); SELECT b.*, A.value1, A.value2, A.value3, A.value4, A.value5, A.value6, FROM table1 b LEFT JOIN table2A ON b.order_no = A.order_no AND b.channel_no = A.channel_no WHERE 1 = 1 AND b.order_no IN (SELECT ticket_order_no FROM tmp_order_no) ORDER BY CREATE_TIME LIMIT 0, 20 DROP TEMPORARY TABLE IF EXISTS tmp_order_no;
優化后查詢時間1.2S左右,速度提升十幾倍,性能提升明顯