Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
從系統(tǒng)設(shè)計角度看,一個系統(tǒng)從設(shè)計搭建到數(shù)據(jù)逐步增長,SQL 執(zhí)行效率可能會出現(xiàn)劣化,為繼續(xù)支撐業(yè)務(wù)發(fā)展,我們需要對慢 SQL 進行分析和優(yōu)化,嚴峻的情況下甚至需要對整個系統(tǒng)進行重構(gòu)。所以我們往往需要在系統(tǒng)設(shè)計前對業(yè)務(wù)進行充分調(diào)研、遵守系統(tǒng)設(shè)計規(guī)范,在系統(tǒng)運行時定期結(jié)合當前業(yè)務(wù)發(fā)展情況進行系統(tǒng)瓶頸的分析。
從數(shù)據(jù)庫角度看,每個 SQL 執(zhí)行都需要消耗一定 I/O 資源,SQL 執(zhí)行的快慢,決定了資源被占用時間的長短。假如有一條慢 SQL 占用了 30%的資源共計 1 分鐘。那么在這 1 分鐘時間內(nèi),其他 SQL 能夠分配的資源總量就是 70%,如此循環(huán),當資源分配完的時候,所有新的 SQL 執(zhí)行將會排隊等待。所以往往一條慢 SQL 會影響到整個業(yè)務(wù)。
本文僅討論 MySQL-InnoDB 的情況。
SQL 語句執(zhí)行效率的主要因素
select * from table_demo where type = ? limit ?,?;
優(yōu)化方式一:偏移 id
lastId = 0 or min(id)
do {
select * from table_demo where type = ? and id >{#lastId} limit ?;
lastId = max(id)
} while (isNotEmpty)
優(yōu)化方式二:分段查詢
該方式較方式一的優(yōu)點在于可并行查詢,每個分段查詢互不依賴;較方式一的缺點在于較依賴數(shù)據(jù)的連續(xù)性,若數(shù)據(jù)過于分散,代價較高。
minId = min(id) maxId = max(id)
for(int i = minId; i<= maxId; i+=pageSize){
select * from table_demo where type = ? and id between i and i+ pageSize;
}
提高 GROUP BY 語句的效率, 可以通過將不需要的記錄在 GROUP BY 之前過濾掉.下面兩個查詢返回相同結(jié)果但第二個明顯就快了許多。
低效:
select job , avg(sal) from table_demo group by job having job = ‘manager'
高效:
select job , avg(sal) from table_demo where job = ‘manager' group by job
聯(lián)合索引中如果有某個列存在范圍(大于小于)查詢,其右邊的列是否還有意義?
explain select count(1) from statement where org_code='1012' and trade_date_time >= '2019-05-01 00:00:00' and trade_date_time<='2020-05-01 00:00:00'
explain select * from statement where org_code='1012' and trade_date_time >= '2019-05-01 00:00:00' and trade_date_time<='2020-05-01 00:00:00' limit 0, 100
explain select * from statement where org_code='1012' and trade_date_time >= '2019-05-01 00:00:00' and trade_date_time<='2020-05-01 00:00:00'
以查找 trade_date_time >='2019-05-01' and trade_date_time <='2020-05-01' and org_code='1020'為例:
小結(jié):對于該 case, 索引效果[org_code,trade_date_time] > [trade_date_time, org_code]>[trade_date_time]。實際業(yè)務(wù)場景中,檢索條件中 trade_date_time 基本上肯定會出現(xiàn),但 org_code 卻不一定,故索引的設(shè)計還需要結(jié)合實際業(yè)務(wù)需求。
索引:
KEY `idx_account_trade_date_time` (`account_number`,`trade_date_time`),
KEY `idx_trade_date_times` (`trade_date_time`)
KEY `idx_createtime` (`create_time`),
慢 SQL:
SELECT id,....,creator,modifier,create_time,update_time FROM statement
WHERE (account_number = 'XXX' AND create_time >= '2022-04-24 06:03:44' AND create_time <= '2022-04-24 08:03:44' AND dc_flag = 'C') ORDER BY trade_date_time DESC,id DESC LIMIT 0,1000;
優(yōu)化前:SQL 執(zhí)行超時被 kill 了
SELECT id,....,creator,modifier,create_time,update_time FROM statement
WHERE (account_number = 'XXX' AND create_time >= '2022-04-24 06:03:44' AND create_time <= '2022-04-24 08:03:44' AND dc_flag = 'C') ORDER BY create_time DESC,id DESC LIMIT 0,1000;
優(yōu)化后:執(zhí)行總行數(shù)為:6 行,耗時 34ms。
MySQL使不使用索引與所查列無關(guān),只與索引本身,where條件,order by 字段,group by 字段有關(guān)。索引的作用一個是查找,一個是排序。
select * from order where status='S' and update_time < now-5min limit 500
拆分優(yōu)化:
隨著業(yè)務(wù)數(shù)據(jù)的增長 status='S'的數(shù)據(jù)基本占據(jù)數(shù)據(jù)的 90%以上,此時該條件無法走索引。我們可以結(jié)合業(yè)務(wù)特征,對數(shù)據(jù)獲取按日期進行拆分。
date = now; minDate = now - 10 days
while(date > minDate) {
select * from order where order_date={#date} and status='S' and update_time < now-5min limit 500
date = data + 1
}
SQL 檢查狀態(tài)及分數(shù)計算邏輯
MySQL 邏輯架構(gòu)圖:
優(yōu)點
缺點
普通索引
組合索引
索引頁結(jié)構(gòu)
索引頁由七部分組成,其中 Infimum 和 Supremum 也屬于記錄,只不過是虛擬記錄,這里為了與用戶記錄區(qū)分開,還是決定將兩者拆開。
MySQL 有 4 種存儲格式:
Dynamic 行存儲格式下,對于處理行溢出(當一個字段存儲長度過大時,會發(fā)生行溢出)時,僅存放溢出頁內(nèi)存地址。
哪些情況適合建索引
哪些情況下不需要使用索引
例如有一張表 user,主鍵 id,普通字段 age,為 age 創(chuàng)建非聚集索引,有一條查詢語句 select* user from table where age > 18;(注意查詢語句中的結(jié)果是*)
在 MySQL5.5 以及之前的版本中如何查詢呢?先通過非聚集索引查詢到 age>18 的第一條數(shù)據(jù),獲取到了主鍵 id;然后根據(jù)非聚集索引中的葉子節(jié)點存儲的主鍵 id 去聚集索引中查詢行數(shù)據(jù);根據(jù) age>18 的數(shù)據(jù)條數(shù)每次查詢聚集索引,這個過程叫做回表。
上述的步驟有什么缺點呢?如何 age>18 的數(shù)據(jù)非常多,那么每次回表都需要經(jīng)過 3 次 IO(假設(shè) B+樹的高度是 3),那么會導(dǎo)致查詢效率過低。
在 MySQL5.6 時針對上述問題進行了優(yōu)化,優(yōu)化器先查詢到 age>3 的所有數(shù)據(jù)的主鍵 id,對所有主鍵的 id 進行排序,排序的結(jié)果緩存到 read_rnd_buffer,然后通過排好序的主鍵在聚簇索引中進行查詢。
如果兩個主鍵的范圍相近,在同一個數(shù)據(jù)頁中就可以之間按照順序獲取,那么磁盤 io 的過程將會大大降低。這個優(yōu)化的過程就叫做 Multi Range Read(MRR) 多返回查詢。
假設(shè)有索引(name, age), 執(zhí)行 SQL: select * from tuser where name like '張%' and age=10;
MySQL 5.6 以后, 存儲引擎根據(jù)(name,age)聯(lián)合索引,找到,由于聯(lián)合索引中包含列,所以存儲引擎直接在聯(lián)合索引里按照age=10過濾。按照過濾后的數(shù)據(jù)再一一進行回表掃描。
索引下推使用條件
索引下推的目的是為了減少回表次數(shù),也就是要減少 IO 操作。對于的聚簇索引來說,數(shù)據(jù)和索引是在一起的,不存在回表這一說。
拋開數(shù)據(jù)庫硬件層面,數(shù)據(jù)庫表設(shè)計、索引設(shè)計、業(yè)務(wù)代碼邏輯、分庫分表策略、數(shù)據(jù)歸檔策略都對 SQL 執(zhí)行效率有影響,我們只有在整個設(shè)計、開發(fā)、運維階段保持高度敏感、追求極致,才能讓我們系統(tǒng)的可用性、伸縮性不會隨著業(yè)務(wù)增長而劣化。
這篇文章中,我將分享21個HTML技巧,包括代碼片段,可以提升你的編碼技能。
讓我們立即開始吧。
(本文視頻講解:java567.com)
針對下拉框選項,可以直接獲取下拉框中的值,然后再循環(huán)獲取匹配,也可以直接通過元素定位直接操作。
針對select/option這樣下拉選擇框,如圖展示:
我們可以直接使用webdriver中的Select類去處理 。
首先是引入Select類(兩種引包方法):
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.ui import Select
ui.py文件中實際引入的也是 select下的Select類,所以我們引入ui包實際引入的還是Select類:
源碼中Select下有很多方法,專門用于處理下拉選擇框操作:
from selenium import webdriver
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('https://www.w3school.com.cn/tiy/t.asp?f=html_select')
driver.find_element_by_xpath("//a[contains(text(),'運行代碼')]").click()
iframeResult = driver.find_element_by_xpath("//iframe[@id='iframeResult']")
driver.switch_to.frame(iframeResult)
result = Select(driver.find_element(By.CSS_SELECTOR, "body:nth-child(2) > select:nth-child(1)")).options
for i in result:
print(i.text)
運行后的結(jié)果:下拉選擇框中的數(shù)據(jù)循環(huán)打印顯示在控制臺
F:\virtualEnvironment\venv\Scripts\python.exe F:/git/AuomationTest/AuomationTestProject/webTestAuomation/selenium_select.py
Volvo
Saab
Opel
Audi
Process finished with exit code 0
result = Select(driver.find_element(By.CSS_SELECTOR, "body:nth-child(2) > select:nth-child(1)")).all_selected_options
for i in result:
print(i.text)
driver.quit()
運行后的結(jié)果:下拉選擇框中循環(huán)打印被選中的的選項
F:\virtualEnvironment\venv\Scripts\python.exe F:/git/AuomationTest/AuomationTestProject/webTestAuomation/selenium_select.py
Volvo
Process finished with exit code 0
result = Select(driver.find_element(By.CSS_SELECTOR, "body:nth-child(2) > select:nth-child(1)")).first_selected_option
print(result.text)
driver.quit()
運行后的結(jié)果:打印下拉框中第一個被選中的的選項
F:\virtualEnvironment\venv\Scripts\python.exe F:/git/AuomationTest/AuomationTestProject/webTestAuomation/selenium_select.py
Volvo
Process finished with exit code 0
下面示例html代碼:
<!DOCTYPE html>
<html>
<body>
<select>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>
</body>
</html>
例如: select_by_value("volvo"),選擇的就是第一個:" <option value="volvo">Volvo</option> "
例如:select_by_index(1),選擇的就是第二個:" <option value="saab">Saab</option> "
例如:圖片標藍框處的文本信息 ?,select_by_visible_text("Audi"),選擇的就是第四個:" <option value="audi">Audi</option> "
下面示例代碼,僅供參考:
result = Select(driver.find_element(By.CSS_SELECTOR, "body:nth-child(2) > select:nth-child(1)"))
result.select_by_index(1)
for i in result.all_selected_options:
print(i.text)
result.select_by_value("opel")
for i in result.all_selected_options:
print(i.text)
result.select_by_visible_text("Audi")
for i in result.all_selected_options:
print(i.text)
time.sleep(10)
driver.quit()
運行后的結(jié)果:每一個獲到參數(shù)的方法全部都做了循環(huán)并打印到控制臺
F:\virtualEnvironment\venv\Scripts\python.exe F:/git/AuomationTest/AuomationTestProject/webTestAuomation/selenium_select.py
Saab
Opel
Audi
Process finished with exit code 0
result = Select(driver.find_element(By.CSS_SELECTOR, "body:nth-child(2) > select:nth-child(1)"))
result.deselect_by_index(1)
result.deselect_by_value("opel")
result.deselect_by_visible_text("Audi")
result.deselect_all()
time.sleep(10)
driver.quit()
deselect_xxxxxxx開頭的方法,就是取消選中操作的意思,如果沒有指定值存在就會拋異常:NotImplementedError, 取消的方法其實就是跟選中的方法一樣操作,無非就是先選中后再進行取消操作,在此就不再多作敘述,可自行實操下效果...
以上總結(jié)或許能幫助到你,或許幫助不到你,但還是希望能幫助到你,如有疑問、歧義,評論區(qū)留言會及時修正發(fā)布,謝謝!
未完,待續(xù)…
一直都在努力,希望您也是!
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。