1. 程式人生 > >代碼變量拆分大SQL

代碼變量拆分大SQL

數據庫

關於xxx的慢查改進建議:

1、註意不要使用 *,查表時應具體指明列名

2、避免使用子查詢

3、聯表/分步查詢時,先將範圍縮小

4、可以在應用內存中完成的運算,不要交給數據庫

這是兩個比較急需解決的,後續下次再溝通

一、

select

t.*,

CASE c.card_type

WHEN ‘debit‘ THEN ‘xxx‘

WHEN ‘prepaid‘ THEN ‘xxx‘

WHEN ‘credit‘ THEN ‘xxx‘

WHEN ‘semiCredit‘ THEN ‘xxx‘ END ‘card_type‘,

c.cardbin_name, c.issuer_name, a.name acquirer_name, m.merchant_name,am.merchant_name

from ((((

trans_history t

join dict_cardbin c on t.cardbin_id = c.id )

left join cm_merchant m on t.merchant_id=m.id)

left join acquirer a on t.acquirer_id = a.id )

left join acq_merchant am on t.acq_merchant_id = am.id )

left join agency ag on m.agency_id = ag.id

order by t.id desc

limit 0, 20;

trans_history這個表非常大,有5G

, 整表掃描代價也是非常大的。可否根據這個表的訪問需求,將老數據分出來一部分。


其他幾個表比較小。但是,這個查詢只需要trans_history中最新的20條id,而聯表動作會將整表連接,再排序。所需的時間代價是整掃trans_history的基礎上再翻數倍,類似於O(M*N*T...)


dict_cardbin、cm_merchant、acquirer、acq_merchant、agency的id均為主鍵的情況下,我們每個表只檢索20條記錄是非常快的。相當於O(M+N+T...)


建議改為:


第一步查主表,20條記錄

sql = select id, col1, col2,..., cardbin_id, merchant_id, acquirer_id, acquirer_id, acq_merchant_id from trans_history order by id desc limit 20;

rowset = sql_query(sql)

組合下一步查詢所需id字符串

cardbin_id_str = ‘,‘,join(str(row.cardbin_id) for row in rowset) //形式為 "id1, id2, id3...., id20"

第二步查分支表:

cardbin_sql = select id, card_type, cardbin_name, issuer_name from dict_cardbin where id in ($cardbin_id_st)

cardbin_rowset = sql_query(cardbin_sql)

依次類推

card_type比較少,直接放在程序內存

card_type_map = {"debit":"借記卡", ...}


最終結果:

for row in rowset:

print row.id, row.col1, row.col2..., card_type_map[cardbin_rowset[id].card_type], cardbin_rowset[id].cardbin_name, cardbin_rowset[id].issuer_name, acquirer_rowset[id].name, cm_merchant_rowset[id].merchant_name , acq_merchant_rowset[id].merchant_name

二、

SELECT temp.id, temp.acq_merchant_id, temp.enabled, temp.batch_no, temp.trace_no,temp.terminal_no,temp.merchant_no

from (

SELECT c.*,b.merchant_no,ks.key_alias

from acq_merchant_terminal c

LEFT JOIN acq_merchant b on b.id=c.acq_merchant_id

JOIN acquirer a on a.id=b.acquirer_id

LEFT JOIN key_store ks on ks.key_alias = CONCAT(%s,c.terminal_no,%s) OR ks.key_alias = CONCAT(%s,c.terminal_no,%s)

WHERE a.enabled=%n and b.enabled=%n and and a.`code`= %s) temp

WHERE temp.key_alias is NULL;

這幾個表數據量都不算太大,可以聯表

我們在聯表/分步時,應註意先使用限制條件,將檢索範圍縮小,因此,將限制主表行數的條件提前。

select c.id, c.acq_merchant_id, c.enabled , c.batch_no c.trace_no, c.terminal_no, b.merchant_no, b.key_alias //註意不要使用*,明確列出列名

from acq_merchant_terminal c

left join acq_merchant b on b.id=c.acq_merchant_id

join acquirer a on a.id=b.acquirer_id

left join key_store ks on ks.key_alias in (concat(%s,c.terminal_no,%s)) //為什麽原sql寫了兩遍這個條件?註意應盡量避免使用OR連接檢索條件,如果有多個值,使用 in (值列表)

where c.enabled=%n and a.enabled=%n and a.code= %s and b.enabled=%n

mysql> select count(c.id) from acq_merchant_terminal c left join acq_merchant b on b.id=c.acq_merchant_id join acquirer a on a.id=b.acquirer_id left join key_store ks on ks.key_alias in ("acq.ryxpay.88779g648160001.79g60001.zmk") where c.enabled=1 and a.enabled=1 and a.code= "ryxpay" and b.enabled=1;

+-------------+

| count(c.id) |

+-------------+

| 90617 |

+-------------+

1 row in set (0.33 sec)

外層檢索邏輯key_alias是否為null,可用程序完成:

for row in rowset:

if row.key_alias != NULL:

......



--同事寫的。

本文出自 “晴空” 博客,謝絕轉載!

代碼變量拆分大SQL