新聞中心
?譯者 | 李睿

望謨網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)公司等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)于2013年成立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
審校 | 孫淑娟
SQL開發(fā)商Data Geeker公司首席執(zhí)行官Lukas Eder日前表示,他在博客文章列出了Java開發(fā)人員在編寫SQL時(shí)常犯的10個(gè)錯(cuò)誤。這篇文章得到廣泛關(guān)注,這讓他感到非常驚訝。這種受歡迎程度說(shuō)明了幾點(diǎn):
- SQL對(duì)于專業(yè)的Java世界有多重要。
- 忘記一些基本的SQL內(nèi)容是多么常見。
- 以SQL為中心的庫(kù)(例如jOOQ或MyBatis)是如何通過(guò)采用SQL來(lái)響應(yīng)市場(chǎng)需求的。
一個(gè)有趣的事實(shí)是,用戶甚至在slick的郵件列表中提到了他寫的博客文章。Slick是Scala中的一個(gè)不以SQL為中心的數(shù)據(jù)庫(kù)訪問(wèn)庫(kù)。和LINQ(以及LINQ-TO-SQL)一樣,它關(guān)注的是語(yǔ)言集成,而不是SQL代碼生成。
無(wú)論如何,Eder列出的一些錯(cuò)誤還遠(yuǎn)遠(yuǎn)不夠,下面將介紹Java開發(fā)人員在編寫SQL時(shí)常犯的10個(gè)錯(cuò)誤。
1.不使用預(yù)處理語(yǔ)句(Prepared Statements)
有趣的是,在JDBC出現(xiàn)多年之后,這種錯(cuò)誤或誤解仍然出現(xiàn)在博客、論壇和郵件列表中,即使它是關(guān)于一個(gè)在記憶和理解方面非常簡(jiǎn)單的的事情。一些開發(fā)人員似乎因?yàn)橐韵略蚨苊馐褂妙A(yù)處理語(yǔ)句:
- 不知道預(yù)處理語(yǔ)句。
- 認(rèn)為預(yù)處理語(yǔ)句速度較慢。
- 認(rèn)為編寫預(yù)處理語(yǔ)句需要花費(fèi)更多的精力。
首先需要打破以上誤區(qū)。在96%的情況下,編寫預(yù)處理語(yǔ)句要比編寫靜態(tài)語(yǔ)句更好。為什么?其原因很簡(jiǎn)單:
- 在內(nèi)聯(lián)綁定值時(shí),可以省略由錯(cuò)誤的字符串連接引起的語(yǔ)法錯(cuò)誤。
- 當(dāng)內(nèi)聯(lián)綁定值時(shí),可以忽略由于字符串連接錯(cuò)誤造成的SQL注入漏洞。
- 當(dāng)內(nèi)聯(lián)更復(fù)雜的數(shù)據(jù)類型(如時(shí)間戳、二進(jìn)制數(shù)據(jù)等)時(shí),可以避免使用邊緣用例。
- 可以讓打開的預(yù)處理語(yǔ)句保留一段時(shí)間,用新的bind值重用它們,而不是立即關(guān)閉它們(例如,在postgres中很有用)。
- 可以在更復(fù)雜的數(shù)據(jù)庫(kù)中使用自適應(yīng)游標(biāo)共享(Oracle語(yǔ)言)。這有助于防止對(duì)每一組新的綁定值進(jìn)行硬解析SQL語(yǔ)句。
需要注意的是,在極少數(shù)情況下,確實(shí)需要內(nèi)聯(lián)綁定值,以便讓數(shù)據(jù)庫(kù)的基于成本的優(yōu)化器了解真正將受到查詢影響的數(shù)據(jù)類型。通常,這會(huì)導(dǎo)致“常量”謂詞,例如:
- deleted = 1
- status = 42
但它不應(yīng)該導(dǎo)致“變量”謂詞,例如:
- first_name like “jon%”
- amount > 19.95
需要注意的是,現(xiàn)代數(shù)據(jù)庫(kù)實(shí)現(xiàn)了綁定變量窺視。因此,在默認(rèn)情況下,還可以為所有查詢參數(shù)使用綁定值。另外,在編寫嵌入式JPQL或嵌入式SQL時(shí),諸如JPA CriteriaQuery或jOOQ等高級(jí)API將幫助您生成預(yù)處理語(yǔ)句并非常容易和透明地綁定值。
解決辦法:
在默認(rèn)情況下,總是使用預(yù)處理語(yǔ)句而不是靜態(tài)語(yǔ)句,并且永遠(yuǎn)不要將綁定值內(nèi)聯(lián)到SQL中。
2.返回太多的列
這種錯(cuò)誤非常常見,可能會(huì)在數(shù)據(jù)庫(kù)的執(zhí)行計(jì)劃和Java應(yīng)用程序中導(dǎo)致非常糟糕的影響。先看看第二個(gè)效果:
(1)對(duì)Java應(yīng)用程序的不良影響
如果選擇*(星號(hào))或50列的“默認(rèn)”集合(在各種數(shù)據(jù)訪問(wèn)對(duì)象之間重用),則需要將大量數(shù)據(jù)從數(shù)據(jù)庫(kù)傳輸?shù)絁DBC結(jié)果集。即使沒有從結(jié)果集中讀取數(shù)據(jù),它也已經(jīng)通過(guò)網(wǎng)絡(luò)傳輸,并由JDBC驅(qū)動(dòng)程序加載到內(nèi)存中。如果知道只需要2~3個(gè)這樣的列,這相當(dāng)浪費(fèi)IO和內(nèi)存。
這是顯而易見的,但也要小心。
(2)對(duì)數(shù)據(jù)庫(kù)執(zhí)行計(jì)劃的不良影響
這些影響實(shí)際上可能比對(duì)Java應(yīng)用程序的影響要嚴(yán)重得多。復(fù)雜的數(shù)據(jù)庫(kù)在為查詢計(jì)算最佳執(zhí)行計(jì)劃時(shí)執(zhí)行大量SQL轉(zhuǎn)換。很可能查詢的某些部分可以被轉(zhuǎn)換掉,因?yàn)橹浪鼈儾粫?huì)對(duì)投影(選擇子句)或過(guò)濾謂詞產(chǎn)生影響。
考慮一個(gè)復(fù)雜的選擇,它將連接兩個(gè)視圖:
select *
from customer_view c
join order_view o
on c.cust_id = o.cust_id
onc.cust_id=o.cust_id
連接到上述連接表引用的每個(gè)視圖可能再次連接來(lái)自幾十個(gè)表的數(shù)據(jù),例如customeraddress、order history、order settlement等??紤]到select*投影,數(shù)據(jù)庫(kù)別無(wú)選擇,只能完全加載所有這些聯(lián)接表,而實(shí)際上,唯一感興趣的是:
select c.first_name, c.last_name, o.amount
from customer_view c
join order_view o
on c.cust_id = o.cust_id
一個(gè)出色的數(shù)據(jù)庫(kù)將以一種可以刪除大部分“隱藏”連接的方式轉(zhuǎn)換SQL,這將顯著地減少數(shù)據(jù)庫(kù)中的IO和內(nèi)存消耗。
解決方法:
從不執(zhí)行select*。不要為不同的查詢重用相同的投影??偸菄L試減少投影到真正需要的數(shù)據(jù)。
注意,用對(duì)象關(guān)系映射(ORM)很難實(shí)現(xiàn)這一點(diǎn)。
3.認(rèn)為join是select子句
這并不是一個(gè)對(duì)性能或SQL正確性有很大影響的錯(cuò)誤,但是,SQL開發(fā)人員應(yīng)該意識(shí)到這樣一個(gè)事實(shí):join子句本身不是select語(yǔ)句的一部分。sql standard 1992這樣定義表引用:
6.3


咨詢
建站咨詢
