代碼變量拆分大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