mysql高效查询_mysql 高效率查询背景
說起mysql查詢效率問題,就無法繞開索引問題,而innodb索引是mysql存儲(chǔ)引擎中的重中之重,innodb索引包括“主鍵索引(聚集索引)”也就是實(shí)際數(shù)據(jù)和主鍵數(shù)據(jù)存儲(chǔ)在一起的索引。innodb除了主鍵索引以外就是二級索引,二級索引葉子結(jié)點(diǎn)的數(shù)據(jù)區(qū)存儲(chǔ)的是主鍵,mysql每個(gè)數(shù)據(jù)頁面有16k大小,innodb在執(zhí)行插入數(shù)據(jù)后就已經(jīng)根據(jù)唯一鍵將數(shù)據(jù)頁排好順序,索引結(jié)構(gòu)暫時(shí)不做過多解釋。
那我們新建二級索引的時(shí)可以根據(jù)“近1”原則創(chuàng)建,創(chuàng)建是參考sql語句:select ?COUNT(DISTINCT(CONCAT(date,name)))/count(*) ;
例如,想要建立兩個(gè)字段的聯(lián)合索引,而第二個(gè)字段你可以選擇使用前綴的創(chuàng)建方式,也就是第二個(gè)字段只使用部分?jǐn)?shù)據(jù)。
比如查詢優(yōu)化中我們要遵循最佳做前綴原則,這個(gè)時(shí)候我們很可能想根據(jù)后綴去查詢,我們可以將數(shù)據(jù)倒置后,存儲(chǔ)冗余一列在按照左匹配模糊查詢。
如網(wǎng)址列查詢我們可以存儲(chǔ)為:moc.udiab.www 這種形式。
按照創(chuàng)建索引涉及的列去重后的總數(shù)和數(shù)據(jù)總數(shù)做對比,結(jié)果越趨近于1,則索引查詢效果越好。因?yàn)樵节吔?說明數(shù)據(jù)差距不大,所掃描的數(shù)據(jù)代價(jià)越高。
=========JOIN=========
先說下join吧,兩個(gè)表的join操作,實(shí)質(zhì)是將一張表的記錄放入另一張表進(jìn)行匹配過濾,mysql有join_buffer_size設(shè)置,這個(gè)設(shè)置會(huì)決定每次從驅(qū)動(dòng)表中拿出多少條數(shù)據(jù)去另一張表做過濾,如果內(nèi)存允許的話,盡量將其調(diào)大(默認(rèn)256KB)這樣會(huì)減少IO開銷,每次拿驅(qū)動(dòng)表中多的數(shù)據(jù)去和另一張表的數(shù)據(jù)作匹配,sql優(yōu)化器會(huì)試圖將兩個(gè)表的操作先優(yōu)化為內(nèi)連接也就是inner join,這樣做可以使用驅(qū)動(dòng)表優(yōu)化策略,會(huì)將小表設(shè)置為驅(qū)動(dòng)表。
========子查詢========
子查詢的性能也是關(guān)鍵,子查詢可以分為相關(guān)子查詢和獨(dú)立子查詢;每種查詢方式又分為標(biāo)量子查詢(返回單條記錄)和結(jié)果集子查詢。
(1)如:select * from td1 where name=(select a from td2 where td2.b=td1.c limit 1) ?相關(guān)子查詢中的標(biāo)量子查詢;
其實(shí)相關(guān)標(biāo)量子查詢,如果子查詢內(nèi)能夠使用索引速度也是基本沒什么問題的,因?yàn)樗鼤?huì)在外層查詢中先取出一條數(shù)據(jù),然后去子查詢中做唯一匹配,雖然稍復(fù)雜些,但是性能損耗可以接受
(2)如:select * from td1 where name in (select a from td2) 獨(dú)立子查詢;
ps:如果是上面這種則相對復(fù)雜了很多,如果子查詢的返回結(jié)果數(shù)量沒有超過mysql服務(wù)的預(yù)設(shè)值(tmp_table_size),則會(huì)以memory引擎創(chuàng)建一個(gè)td2?臨時(shí)表并創(chuàng)建Hash索引,因?yàn)閠d1中是以等值方式去td2中匹配的;超過了就會(huì)創(chuàng)建磁盤物理表并建立B+Tree索引。
《2.1》針對于in子查詢,查詢優(yōu)化器會(huì)將in優(yōu)化為join,那么轉(zhuǎn)換為join的情況則不同,獨(dú)立子查詢?nèi)绻硬樵兎祷財(cái)?shù)據(jù)庫唯一鍵,則直接可轉(zhuǎn)成join。
《2.2》如果子查詢返回非唯一鍵,則會(huì)使用物化表(按照ps的規(guī)則),將結(jié)果集先去重,然后在進(jìn)行join。
(3)如:select * from td1 where name in (select a from td2 where td1.a=td2.b) 相關(guān)子查詢中使用了主鍵;
相關(guān)子查詢?nèi)ブ睾笤谶M(jìn)行semi join,使用以下命令選擇開啟:
semijoin={on|off}
materialization={on|off}
loosescan={on|off}
subquery_materialization_cost_based={on|off}
4種情況:
《3.1》如果子查詢中select返回是數(shù)據(jù)庫唯一鍵 ,情況也是直接轉(zhuǎn)換為semi join。
《3.2》mysql會(huì)創(chuàng)建一個(gè)臨時(shí)表,每次將主表數(shù)據(jù)取出后在子查詢表中查找數(shù)據(jù),查找到以后插入臨時(shí)表,該臨時(shí)表中不會(huì)有重復(fù)的數(shù)據(jù),當(dāng)數(shù)據(jù)插入完畢以后,在與臨時(shí)表做semi join。
《3.3》使用FirstMatch方法在子查詢表中返回一條語句后,即返回,不在向后繼續(xù)尋找。
《3.4》使用LooseScan,依賴本身的索引,進(jìn)行g(shù)roup by進(jìn)行去重后,在semi join
==================
mysql查詢部分包括,(1)sql執(zhí)行器,(2)sql優(yōu)化器。
sql優(yōu)化的執(zhí)行過程可以先開啟sql優(yōu)化日志后(SET optimizer_trace='enabled=on';),到information_schema.OPTIMIZER_TRACE這個(gè)表中進(jìn)行優(yōu)化過程的查詢,結(jié)合查詢計(jì)劃就能夠看到mysql究竟是怎樣執(zhí)行最終的sql的。
查詢優(yōu)化日志中,我們可以主要觀察where條件優(yōu)化,join優(yōu)化,和analyzing_range_alternatives查詢成本優(yōu)化。
這里我們可以拿analysisi_query_cost查詢成本優(yōu)化為例,row查詢默認(rèn)開銷因子為0.2,主鍵索引數(shù)據(jù)頁查詢因子為1,按照公式=主鍵索引數(shù)據(jù)頁*1+行數(shù)*0.2,最終獲得查詢成本cost的值,優(yōu)化器會(huì)根據(jù)cost值,取最小的執(zhí)行查詢。
{"steps": [
{"join_preparation": {"select#": 1,"steps": [
{"expanded_query": "/* select#1 */ select `t_day_stock`.`STOCK` AS `STOCK`,`t_day_stock`.`DATE` AS `DATE`,`t_day_stock`.`OPEN` AS `OPEN`,`t_day_stock`.`CLOSE` AS `CLOSE`,`t_day_stock`.`HIGH` AS `HIGH`,`t_day_stock`.`LOW` AS `LOW`,`t_day_stock`.`VOLUME` AS `VOLUME`,`t_day_stock`.`VALUE` AS `VALUE`,`t_day_stock`.`NUMBER_OF_TRADES` AS `NUMBER_OF_TRADES`,`t_day_stock`.`PRECLOSE` AS `PRECLOSE` from `t_day_stock` where ((`t_day_stock`.`STOCK` = '600228.SH') and (`t_day_stock`.`DATE` < '2004-01-12'))"}
]
}
},
{"join_optimization": {"select#": 1,"steps": [
{"condition_processing": {"condition": "WHERE","original_condition": "((`t_day_stock`.`STOCK` = '600228.SH') and (`t_day_stock`.`DATE` < '2004-01-12'))","steps": [
{"transformation": "equality_propagation","resulting_condition": "((`t_day_stock`.`STOCK` = '600228.SH') and (`t_day_stock`.`DATE` < '2004-01-12'))"},
{"transformation": "constant_propagation","resulting_condition": "((`t_day_stock`.`STOCK` = '600228.SH') and (`t_day_stock`.`DATE` < '2004-01-12'))"},
{"transformation": "trivial_condition_removal","resulting_condition": "((`t_day_stock`.`STOCK` = '600228.SH') and (`t_day_stock`.`DATE` < '2004-01-12'))"}
]
}
},
{"table_dependencies": [
{"table": "`t_day_stock`","row_may_be_null": false,"map_bit": 0,"depends_on_map_bits": [
]
}
]
},
{"ref_optimizer_key_uses": [
{"table": "`t_day_stock`","field": "STOCK","equals": "'600228.SH'","null_rejecting": false},
{"table": "`t_day_stock`","field": "STOCK","equals": "'600228.SH'","null_rejecting": false},
{"table": "`t_day_stock`","field": "STOCK","equals": "'600228.SH'","null_rejecting": false}
]
},
{"rows_estimation": [
{"table": "`t_day_stock`","range_analysis": {"table_scan": {"rows": 425496,"cost": 98608},"potential_range_indices": [
{"index": "PRIMARY","usable": true,"key_parts": ["STOCK","DATE"]
},
{"index": "stock_date","usable": true,"key_parts": ["STOCK","DATE"]
},
{"index": "stock","usable": true,"key_parts": ["STOCK"]
},
{"index": "date","usable": true,"key_parts": ["DATE"]
}
],"setup_range_conditions": [
],"group_index_range": {"chosen": false,"cause": "not_group_by_or_distinct"},"analyzing_range_alternatives": {"range_scan_alternatives": [
{"index": "PRIMARY","ranges": ["600228.SH <= STOCK <= 600228.SH AND DATE < 2004-01-12 00:00:00"],"index_dives_for_eq_ranges": true,"rowid_ordered": false,"using_mrr": false,"index_only": false,"rows": 3,"cost": 4.61,"chosen": true},
{"index": "stock_date","ranges": ["600228.SH <= STOCK <= 600228.SH AND DATE < 2004-01-12 00:00:00"],"index_dives_for_eq_ranges": true,"rowid_ordered": false,"using_mrr": false,"index_only": false,"rows": 5,"cost": 7.01,"chosen": false,"cause": "cost"},
{"index": "stock","ranges": ["600228.SH <= STOCK <= 600228.SH"],"index_dives_for_eq_ranges": true,"rowid_ordered": true,"using_mrr": false,"index_only": false,"rows": 468,"cost": 562.61,"chosen": false,"cause": "cost"},
{"index": "date","ranges": ["DATE < 2004-01-12 00:00:00"],"index_dives_for_eq_ranges": true,"rowid_ordered": false,"using_mrr": false,"index_only": false,"rows": 7450,"cost": 8941,"chosen": false,"cause": "cost"}
],"analyzing_roworder_intersect": {"usable": false,"cause": "too_few_roworder_scans"}
},"chosen_range_access_summary": {"range_access_plan": {"type": "range_scan","index": "PRIMARY","rows": 3,"ranges": ["600228.SH <= STOCK <= 600228.SH AND DATE < 2004-01-12 00:00:00"]
},"rows_for_plan": 3,"cost_for_plan": 4.61,"chosen": true}
}
}
]
},
{"considered_execution_plans": [
{"plan_prefix": [
],"table": "`t_day_stock`","best_access_path": {"considered_access_paths": [
{"access_type": "ref","index": "PRIMARY","rows": 4254,"cost": 5105.8,"chosen": true},
{"access_type": "ref","index": "stock_date","rows": 310,"cost": 372,"chosen": true},
{"access_type": "ref","index": "stock","rows": 468,"cost": 561.6,"chosen": false},
{"access_type": "range","rows": 3,"cost": 5.21,"chosen": true}
]
},"cost_for_plan": 5.21,"rows_for_plan": 3,"chosen": true}
]
},
{"attaching_conditions_to_tables": {"original_condition": "((`t_day_stock`.`STOCK` = '600228.SH') and (`t_day_stock`.`DATE` < '2004-01-12'))","attached_conditions_computation": [
],"attached_conditions_summary": [
{"table": "`t_day_stock`","attached": "((`t_day_stock`.`STOCK` = '600228.SH') and (`t_day_stock`.`DATE` < '2004-01-12'))"}
]
}
},
{"refine_plan": [
{"table": "`t_day_stock`","pushed_index_condition": "((`t_day_stock`.`STOCK` = '600228.SH') and (`t_day_stock`.`DATE` < '2004-01-12'))","table_condition_attached": null,"access_type": "range"}
]
}
]
}
},
{"join_explain": {"select#": 1,"steps": [
]
}
}
]
}
總結(jié)
以上是生活随笔為你收集整理的mysql高效查询_mysql 高效率查询背景的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 带你梳理一遍 Android 核心知识
- 下一篇: linux cmake编译源码,linu