CSS

Showing posts with label translated. Show all posts
Showing posts with label translated. Show all posts

[Translation]The SQL high performence series part II

偷懶了兩個月沒有寫文章,目前差不多也適應了新的環境
就以利用空閒時間翻譯的這篇文章作為blog復活的開始吧

原文:The SQL high performence series part II
這篇文章是三篇系列文的第二篇(不過作者於第三篇富監了),裡面對索引以及資料庫是如何決定搜尋計畫有不錯的說明


基本?我們可都是專家!


大部分於這篇文章中提到的內容對許多開發者都是老生常談, 但還是值得複習 – 即使在專家之間對於資料庫的基礎,以及影響系統表現的重大原因,都還是留有誤解以及矛盾的資訊. 我將這篇文章寫的比較像一篇演講,而不是一張」重要清單」,但如果你只想看結論可以直接按End


Data Size

這需要在這裡被強調是因為有越來越多的"data wasters" 錯誤的相信只要他們浪費越多,這個專案就會越像一個"企業解決方案",我跳入這個泥沼,知道有些賺飽口袋的反對者會有"你在說謊"之類的回應,不過如果這樣做能夠多省下一byte tree的資料,我願意付出這個代價.

最小化你的資料,當你不需要GUID的時候,不要用GUID(例如:你不需要做跨全域的複製以及不重複的ID時),不要用bigint當你只需要int或small int, 不要用small int 當一個 tiny int就可以滿足需求,用varchar當你不需要nvarchar.使用最小並適合的資料型態,不要到了要刪減過大的資料時,才使用不明確的packing技巧或是原生資料型別.

當然你應該計畫現實上有可能的成長, 而且我並不是在鼓吹你需要用一個tinyint來儲存你的CustomerID欄位,但是在設計你的應用程式時要有一個合理的標準 – 你真的會有超過兩億的使用者嗎?你的應用程式會有32767種語言嗎? 有可能我們會面對一個需有兩億個月份的日曆系統嗎?

去估計在資料庫中使用這些大類別儲存較小的資料是不是可接受的妥協,這會增加效能,並且允許你能簡單的升級你的資料型別,當那些不太可能發生的需求成真的時候。

很明顯的有需多案子確實需要大資料型別的保障,但太多DBA用GUID或BigInt儲存資料以防萬一,來逃避效率上的責任(建立GUID也要花費資源,並且會增加儲存以及I/O的花費,當GUID被用來記錄網路卡的MAC位置時,GUID是循序性的,但現在Windows上的GUID只是單純的亂數, 作為叢集主鍵將會導致無止境的資料重新排列)

這有什麼重要的?在實際的企業應用程式中,有好幾百萬的資料列在資料庫中,而又需要從像冰河一樣緩慢的儲存系統中讀取與寫入資料 – 在這些有限的資源中, 使用1MB來傳輸20000筆記錄不是比5000筆記錄來的好嗎? 10%的資料庫可以儲存到快取記憶體是不是比5%好呢?當然.

不要被那些小規模,所有資料都在記憶體而Query中的計算大於I/O費用的Benchmark所騙. 認為使用大的DataType隻影響了10%左右的表現 – 當你的資料庫進入真正的企業層級時, 尺寸真的很重要(size really does matter). 使用GUID當叢集式索引的主鍵不僅讓你的資料列更大, 也讓非叢集索引更大(並更慢), 當你SAN中最弱的一環正以100%在跑,你會後悔你浪費的每一個byte

索引

許多SQL Server表現上的問題都是源自於沒有或不正確的索引, 或是沒有用到的後補索引. 這常發生在前端專家不情願的接下資料庫的工作時,甚至是發生在由資料庫專家精心打造的資料庫中。
瞭解索引, 並專注於使用它們 , 是高效能資料庫最重要的一點. 不只是建立正確的索引, 還有如何正確的調整現有的索引.

非叢集索引

在參考書中的索引和資料庫中的索引有同樣的意義(並有很多相同的特徵),參考索引你可以快速的找到你想要的資訊,與掃過書裡的每一頁來找尋內容不同,可以直接找到你想要的頁面。在SQL Server的世界中這種索引稱為非叢集索引(non-clustered indexes或是Secondary indexes) - 他們是一個依特定目的而排序資料的子集合,包含了一個指向實體資料列的指標。

在Northwind 資料庫中Order Table的ShipPostalCode是一個非叢集索引的範例。這個索引由ShipPostalCode排序,並可能在下列的Query中使用。

SELECT * FROM Orders WHERE ShipPostalCode = '05022'

如果你看一下執行計畫(當你執行Query時按Ctrl + K 或點選"顯示執行計畫",執行計畫會出現在下方的結果分頁中),你可以看到索引查找(index seek)的發生,並執行一個Bookmark lookup來找到原始的資料列。如果我們在執行以上的Query前先執行SET STATISTICS IO ON,我們會得到此Query的IO使用量統計報告,會像以下這樣:

Table 'Orders'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0.

比較不會使用到索引的以下Query:

SELECT * FROM Orders WITH(INDEX(0)) WHERE ShipPostalCode = '05022'

在這個案例中執行計畫顯示了完整的資料表搜尋(full table scan),IO統計報告如下:

Table 'Orders'. Scan count 1, logical reads 21, physical reads 0, read-ahead reads 0.

在沒有索引的情況下明顯的使用了更多I/O,如果資料量增加到企業級的數量的話,這情況會變得更糟.讓這個事情更糟的是,每一次的資料表搜尋(table scan)會產生Page/row lock, block掉整個資料表的讀取,讓接下來的交易必須等待資料被unlock之後才能確定需要的資料在不在那些被鎖定的資料之中.可是索引查找(index seek)能知道被鎖定的資料並不是他要搜尋的資料,所以不會被影響.試試看同時在兩個分開的查詢視窗中跑兩句query(如果你不能夠在30秒內很快的切換查詢視窗,可以增加WAITFOR的延遲)

BEGIN TRAN

UPDATE Orders SET OrderDate = '1997-08-27'
WHERE OrderID = 10647

WAITFOR DELAY '00:00:30'

ROLLBACK TRAN

第一句使用索引的Query, 會忽略row lock資料列馬上回傳結果,因為被鎖定的資料列並不是這個query所要尋找的. 但第二句沒有使用索引query(可能因為沒有建立索引,或索引不是最佳搜尋選擇),會被block到另一個連線的鎖定解除. 不使用索引不只是非常的沒有效率,當資料庫增加規模時,也可能讓blocking問題顯著的惡化(或在嘗試增加規模時)

叢集式索引

回到我們的譬喻,許多書更進一步的將他們的內容排序,讓資料本身就是排序好的索引,一本料理書可能是按照料理名稱排序,或是一本電話簿是按照城市,姓,名來排列.所以如果你想在這些排好序的資料中搜尋,是非常的有效率的 - 在電話簿的例子中,你可以很快的找到你想找的城市以及姓名,然後在一小筆的資料中掃瞄你想找的人.在SQL server中這種排序叫做叢集式索引.(資料本身的排序),並且有很明顯的原因在一本書或一個資料表中只能有一個叢集式索引.它主要的優點就是所有符合索引的資料都可以迅速的提供,不用其他的參照.

在Northwind資料庫中使用下列的Query:

SELECT * FROM Orders JOIN [Order Details] ON Orders.OrderID = [Order Details].OrderID WHERE Orders.ShipPostalCode = '05022'

如果你檢視執行計畫,Order Details的資料會由一個有效率的索引查找(index seek)來取得.
不過叢集式索引並不是萬靈丹. 例如說,想像你是一個努力工作的打字員,正在維護一本電話簿的排版,然後你小心的將每一筆資料放在正確的頁面上.每次一筆新的資料進來,它並不會正好就符合排序資料的尾端,或是有時候改變已經存在的資訊會同時改變它的排序(例如說Smith先生改名成Jones),你需要重新排列一些頁面已取得空間.這些資料碎片的問題在非叢集與叢集索引都會發生, 但叢集式索引由於包含所有資料,所以這個問題特別嚴重.


當然你可以在每一頁預留一些空間放置這些資料來讓一些小的更動容易些,也就是在SQL Server中fillfactor(填滿因數)的目的(一個較低的fillfactor會在分頁留下更多的空間但會減低真正的資料密度 - 插入資料的速度增加,但讀取資料的表現則減少. 一個較高的fillfactor增加資料密度並提升讀取速度,但增加插入操作時會造成分頁的可能性.注意fillfactor只在索引建立時與重組/重建索引時有用),不規則的插入資料或經常改變叢集式索引欄位可能是會一個嚴重的效能問題.因為這個問題很多開發者使用單一的遞增ID 欄位來作為叢集式索引.歷史上來說有個原因是因為有複數且相同的欄位資料作為索引插入時,全部會被放到相同的索引底下,結果會在這個熱點導致資料的爭奪.SQL Server有邏輯可以解決這些ID欄位並有效的消除這些熱點的問題.


另一個叢集式索引的問題是他們的長度(他們包含了整個資料列的資料). 當你在找某一個特定的資料欄位時,其他資料有可能並不相關,或是你真的計畫在查找後使用所有的資料,但如果你查的是一個範圍內的資料(例如說在Oakville city姓Forbes的人的所有名子)資料庫引擎會使用範圍掃瞄(range scan)讀取整行的資料來找尋符合的資料,再抽出需要的資料. 在我們的電話簿例子中這小小的額外資料並不算什麼,但在真實世界的大型的資料表上可能會導致效能上的衝擊.
考慮如果我們有第二個用city,姓,名來排序的索引,資料庫引擎可以很有效的搜尋這些較小的索引內容.

覆蓋索引(Covering Indexes)

這個帶來一個重點 - 有些索引本身就包含足夠的資訊使你不需要去讀取內容,你的搜尋只要讀取索引就能滿足需求了.考慮一本旅遊書的索引,將有名的景點以國家,城市與名稱排序,然後將你導向更多資訊的頁面,如果你只是想知道義大利的Accademia dell' Arte del Disegno在什麼城市,快速的搜尋索引就可以知道他在Florence. 在這個例子中索引為"覆蓋索引(covering index)",包含了可以覆蓋需求的所有資訊,讓我們不需要去查找資料列來找尋需要的資訊,這常常是最有效的搜尋機制.

變化之前範例中的query:

SELECT OrderID FROM Orders WHERE ShipPostalCode = '05022'

這會很有效的使用ShipPostalCode索引來找尋特定的紀錄,並且這個索引完全可以滿足query本身,所以可以避免消耗資源的bookmark lookup,IO也可以被最小化.

Table 'Orders'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0.

有人應該已經觀察到OrderID實際上並不在索引ShipPostalCode裡,或至少不應該在.但有趣的是所有已排序的資料中的叢集式索引欄位,會自動被加到其他索引的欄位中. 當你需要一個叢集式索引欄位的資料時,有可能非叢集索引的資料會立即滿足你,但也必須衡量它會讓每個其他的索引更大,導致更低的資料密度.

小型的覆蓋式索引是取得資料最有效率的方法,也是一個讓你確認你只取出你實際需要資料的理由.範圍掃瞄(Range Scan)在很多情形下也是很有效率的,並且通常在需要的資料在索引中是連續的的時候,像是你用BETWEEN搜尋兩個日期之間的資料時.雖然因為之前提過的bookmark lookup的花費, 範圍掃瞄(Range Scan)只在索引能完全覆蓋或是使用叢集式索引來搜尋的時候才能看到.

即使在完整的搜尋為必要的時候,索引仍然可能完全覆蓋,考慮加下來加入Customer table的索引:

CREATE INDEX CountryCity ON Customers(Country,City,Address)

這個索引當然包括了Country,City,Address,但如之前提過的它也包含了CustomerID因為它是叢集式索引.單然如果我們搜尋Country,或是Country與City,或是Country,City和Address一個很有效的搜尋或是範圍掃瞄(Range Scan)可能會用來找出符合的資料.

SELECT CustomerID FROM Customers WHERE Country = 'Canada'

如果我們只搜尋address呢?在這個情況下索引不能被用到因為他是先以country再以city與address排序的,所以一個特定的地址有可能出現在索引的任何位址

SELECT CustomerID FROM Customers WHERE Address = '43 rue St. Laurent'

你可能會很驚訝看到它仍然使用了索引, 儘管這次用的是很沒效率的掃瞄(scan)而不是查找(seek).索引因為覆蓋了query所有的敘句和傳回欄位而被使用,且因為索引只是資料的子集合,和資料表掃瞄(scan data table)比起來它使用較少的I/O來掃瞄整個索引

統計資料與bookmark

在之前的例子上我們跑了一個需要bookmark lookup的query(因為他沒有覆蓋索引).query如下:

SELECT * FROM Orders WHERE ShipPostalCode = '05022'

如果你觀看這個query的執行計畫可以看到它在索引中找尋"lookups",並且在叢集式索引上進行bookmark lookup,找尋真正資料列的資料.在這個案例中只有單一的傳回資料列,但即使如此,bookmark lookup的費用還是佔了50%的query運算費用.

bookmark lookup 的花費,是當一個item在索引中被找到,但索引並沒有包含所有需要的資料時所產生的,這也是為什麼很多人驚訝的發現SQL Server忽略了他們認為是完美的索引而使用資料庫掃瞄 (為什麼他們不用我的索引啊啊啊啊!!!). 考慮以下的query

SELECT * FROM Orders WHERE ShipPostalCode = '24100'

從執行計畫你可以看到實際上進行了一個叢集式索引掃瞄 (是用叢集式索引進行的一個資料表掃瞄)來取代使用我們的索引,而且subtree的花費是0.0530
這也許看起來有些複雜,因為我們應該已經有了一個完美的索引,但讓我們重新執行一次相同的query,這次使用一個query hint來強迫他使用我們的索引

SELECT * FROM Orders WITH(INDEX(ShipPostalCode)) WHERE ShipPostalCode = '24100'

你可以從執行計畫上看到它使用了我們的索引,但這次bookmark lookups佔了所有執行時間的80%.我們的subtree花費變成了0.0564 - 比使用資料庫掃瞄還多!

在這個案例中只使用了總共830筆中的10筆記錄(1.2%),而它仍然選擇執行資料庫掃瞄而不是我們的索引.很多開發者都被這個情況迷惑,不知道為什麼SQL Server不使用他們美麗的索引,但資料庫引擎是因為非常實際的理由這樣做的 - 因為這樣比進行非直接從bookmarks的找尋每一小塊資料來的有效率.

當然我們可以儘可能的讓覆蓋索引包含所有必要的資訊來避免bookmark lookups,假設它包含了我們需要從資料表中取得的所有資訊:

SELECT OrderID FROM Orders WHERE ShipPostalCode = '24100'

現在它會使用我們的索引,而且超級有效率. 它的subtree花費只有0.0064.在大型的資料庫這些迴避bookmark lookup與資料表掃瞄的差異可能會非常大.

所以資料庫引擎是如何猜到有多少資料列會符合標準,來決定使用哪個方法最有效率?(不論是索引,bookmark lookup或資料表掃瞄) 這就是分散式統計資料(distribution statistics)派上用場的時候了. 統計資料(Statistics)是一個資料集合,資料庫引擎用來推測哪個計畫在這個查詢上最有效率.你可以用DBCC SHOW_STATISTICS 的指令來看到某些索引的統計資料,在以下的例子中為ShipPostalCode:

DBCC SHOW_STATISTICS('Orders','ShipPostalCode')

因為資料表中的ShipPostalCode是有範圍並分散的號碼,所以在這個例子中統計資料是完全正確的,在一個更實際的資料庫中,有上百萬行的資料列, 統計資料開始更接近估計(錯誤邊際值會逐漸增加),這些資料庫引擎的估計在某些極端的情形下可能會導致完全錯誤的假設,像是預測會產生幾千行資料但實際只用了幾行.

統計資料也可能在複數索引時出錯.在這個案例中可選擇的第一個欄位被使用到,所以之前我們建立的索引(Country,City,Address)因為Country的低辨識性(有很多相同的Country欄位),這個索引經常會被忽略,即使City與Address的結合是非常unique的. 所以普遍來說都建議使用可辨識性最高的欄位作為索引的第一個欄位,在這個案例的索引來說是Address,City,Country. 這是可以討論的因為它讓索引更具有單一的用途-他不再具有增進效率的用途,提供給比較模糊的搜尋像只有Country,或是Country/City. 但這需要依照案例來判斷,而且在一個完整正規化的資料表中,這並不是個問題.

並且需要注意的是,你的統計資料儘可能的接近正確值是很重要的. SQL Server包含了自動更新統計資料,依照預設值,在覺得資料已經過期時會自動嘗試資料取樣與更新統計資料. 但儘管如此,最好的方法還是定期的安排完整的統計資料更新(最少每週),最好使用WITH FULLSCAN 的選項讓結果儘可能的正確. 標準的database維護計畫包含了更新統計資料的步驟,允許你選擇取樣的資料範圍.

但即使依照以上的步驟,你的統計資料仍然有過期的可能. 在這種情況下可能是索引提示需要被加入query,來要求query重新評量. 不過很明顯的這應該是最後才考慮的手段.

實際使用索引

所以你已經建立了美麗的索引,然後你已經確定了你的query只從每個資料表中提取了必需的資料,在可能的地方使用覆蓋索引來避免bookmark lookup的花費. 你使用執行計畫來評量效能,並發現......資料庫引擎完全忽略了你的索引. 以下幾點是可能的原因.

考慮以下的query

SELECT OrderID FROM Orders WHERE LEFT(ShipPostalCode,4) = '0502'

很簡單的query, 而且看起來這像是一個很有效率的覆蓋索引查找(covered index seek). 但執行後會發現這其實是一個沒有效率的掃瞄.考慮下列query:

SELECT OrderID FROM Orders WHERE ShipPostalCode LIKE '0502%'

在這個案例中query以高效率的索引查找(index seek)執行. 我已經有過這種微小的差距讓企業報表產生的時間從幾小時降到幾秒鐘的案例.

原因是因為前一個敘句的索引欄位被隱藏在函式之中. 資料庫引擎不能夠預測函式的結果是什麼,所以他會強迫去計算每一列的來看產生的結果. LIKE是第一級的比較函式,資料庫知道他的行為,所以可以對他做最佳化. 有無數的案例是由於人們沒有必要的將索引欄位放到了函式中,造成了大量與無法預期的效率低落.

最常見的例子是使用DATAADD/DATEDIFF來取得一定時間內的資料列 - 而不用預先計算好的數值(例如: GateDate() - 3 years) 並與資料列進行直接的比對, 開發者強迫整個資料庫掃瞄在每一個資料列上進行無謂的資料比對. 考慮一個從新聞資料表報告12小時內所有新出現新聞的query.

DECLARE @CurrentTime 

SET @CurrentTime = GetDate() 

SELECT * FROM NewsStories WHERE DATEDIFF(hh,NewsDate,@CurrentTime)<12 

我保證這會非常的沒有效率, 但這也是非常普遍的例子. 使用下列變數,資料庫引擎可以更有效的最佳化:

DECLARE @StartTime   
SET @StartTime = DATEADD(hh,-12,GetDate())   
SELECT * FROM NewsStories WHERE NewsDate > @StartTime

資料庫速查表:


索引欄位


在文章開頭我建議你們最小化使用的資料空間(增加實際資料密度). 這個目標並不是要將資料庫移植到一張磁片上,而是最小化查詢計需的磁碟I/O,因為磁碟I/O是企業系統中最脆弱的一環. 當然增加而外的索引,是一個設計上的選擇.它雖然會增加資料庫的大小但卻能減低實際上需要存取的I/O,所以通常都是很值得的交換.

另一個有用的技巧是,你可以以磁碟空間交換資料庫的效能,有很多的變化,但我只提一個最常使用的情形 - 依照年份提供每個月份的報表. 在這個情形下Orders 資料表可能被壓縮成用以下的Query來查詢:

SELECT YEAR(OrderDate) AS [Year], MONTH(OrderDate) AS [Month], COUNT(*) AS [Monthly Orders] 
FROM Orders 
WHERE YEAR(OrderDate)=1997 
GROUP BY YEAR(OrderDate), MONTH(OrderDate)

取代使用串接式的命令來取得年分與月份的資料,考慮把它們加為資料欄位:

ALTER TABLE dbo.Orders ADD 
OrderDateYear  AS CONVERT(smallint,YEAR(OrderDate)), 
OrderDateMonth  AS CONVERT(tinyint,MONTH(OrderDate)) 

現在我們可以把query改成

SELECT OrderDateYear AS [Year], OrderDateMonth AS [Month], COUNT(*) AS [Monthly Orders] 
FROM Orders 
WHERE OrderDateYear=1997 
GROUP BY OrderDateYear, OrderDateMonth

本身我們並沒有用任何方法來增加查詢的效率(事實上查詢效率在變更之後還降低了),雖然我們讓資料庫更複雜化,但我們也建立了一些索引欄位作為建立索引的基礎.

CREATE NONCLUSTERED INDEX IX_OrderDateDecomposed ON dbo.Orders
(
OrderDateYear,
OrderDateMonth
) ON [PRIMARY]
GO

現在參考這些索引欄位的查詢戲劇性的便的非常有效率,更好的是,這些增加的索引欄位並沒有減低實際的資料密度,因為他們只出現在索引中. 注意:確認不需要這些索引欄位的查詢不會外在的或隱含的使用浪費的* column selector, 因為它會不必要為每一個資料列評估這些欄位.


索引視圖

[這個功能只在Enterprise和Developer edition of SQL Server才有]

一個索引視圖,有時候代表了一個具體的視圖,是一個排列後的索引欄位,把儲存計算結果帶到了下一個階段.在一個之前的例子中我們將索引欄位組合在一起來增加資料組合的邏輯效能.我們可以把它做個改變來建立一個視圖(View)

CREATE VIEW dbo.OrdersByMonth
WITH SCHEMABINDING
AS
SELECT OrderDateYear AS [Year], OrderDateMonth AS [Month], COUNT_BIG(*) AS [Monthly Orders]
FROM dbo.Orders
GROUP BY OrderDateYear, OrderDateMonth

這個視圖(View)只是一個查詢的範本,並且只對重用程式碼有用(雖然也是個很有價值的目標).我們可以更進一步的實體化這個視圖(View),儲存結果並更改它,使更改內容能反映到實際的資料.以下的指令可建立一個索引視圖:

CREATE UNIQUE CLUSTERED INDEX IX_OrdersByMonth ON OrdersByMonth(Year,Month)

現在以下的查詢可以滿足索引視圖了,使用預先計算的值來取代每次查詢的重新計算.

SELECT [Year],[Month],[Monthly Orders] FROM OrdersByMonth WHERE Year=1997

最後我們每個月的訂單查詢使用的資源比原本的下降了90%,這還只是在一個很小的sample資料庫的結果.在真實的資料庫中結果可能差距會非常大.

索引視圖的確有缺點,像是會在資料改變的時候執行自動維護,但這可以是一個非常有用的工具,當你的工具箱中有這項工具並且你使用的平台支援它的時候.


結論 :

  • 儘可能保持資料列很小, 增加資料密度
  • 所有的Table都需要叢集式索引,除了一些例外. 通常單一欄位的主鍵就是索引
  • 小的叢集式索引讓非叢集式索引也很小,增加資料密度
  • 叢集式索引可幫助建立其他覆蓋索引
  • 使用覆蓋索引非常的有效率
  • 避免把標準欄位隱藏在函式中 – 他們不能用到索引
  • 當適合的時候使用有索引的欄位
  • 如果你已經花錢買了企業板的資料庫,認真考慮使用索引視圖(indexed view)
  • 索引索引索引!只有很有限的案例中,新增與插入時維持索引的費用會超過它的好處
  • 瞭解執行計畫,定期的去評估它

[Joy of Engineering Leadership]如何失去友誼與離間他人



Google I/O 2010: How to lose friends and alienate people: The joys of engineering leadership

這是Google I/O 中一場有關於如何領導團隊的演講:

以下是Wave上的筆記翻譯:

Ben和Fitz來到台上
這個講題是關於軟體工程的人事方面,大部分是我們的意見,如果你有不同的看法的話,你也可以開一個自己的講題 :-)

這裡有誰是管理者的?很多人舉手…

我們要先定義問題是什麼…如果你有一堆工程師,指派他們去完成一個專案、而沒有指定任何領導人,有人就會成為領導人,去分配工作,解決衝突等等,他們將自己放到更高的角度來看專案。這種情形稱為意外型管理者。

管理者是過時而要被淘汰的,而領導者是最搶手的新玩意。他們從工業革命以來的生產線式管理進化而來。當你要管理的是一個固定的流程時,糖果和鞭子的管理方式是很有用。但是當你要管理的是創意相關的工作時,糖果和鞭子就是一個災難了。

這造成了衝突,也是為什麼大家都討厭管理者的原因。典型的呆伯特式管理者的形象是;缺乏安全感,不受尊重,被雇用來監視大家,關心自己的晉升勝於他的團隊。

在大多數的公司中,傑出的工程師晉升到了頂端後,他們就必須進入管理階層,他們是好的工程師,卻也是不好的管理者。

什麼是Engineering Leader?


- 團隊中去排除障礙,服務團隊的人。
- 團隊中能夠信任的來源。
- 必須要能處理人際,但不能只會處理人際關係,他必須要有足夠的技術能力來了解發生什麼事。
- 最好的領導不是能輕易看見的,而是感覺到的。

ANTIPATTERNS


• 當每個人的朋友
• 你不可能永遠都是每個人的朋友,你必須能告訴大家壞消息,做出決策
• 像小孩一樣對待他人
• 如果你像小孩一樣對待別人,他們就會表現得像小孩。
• 不要Micro manage
• 相信別人會表現得像個大人並作出正確的事
• 如果你micromanage別人,他們就會表現得像小孩一樣。
• 雇用聽話的人:
• 最後你會雇用到只會聽命令辦事的人。
• 你必須要雇用比你聰明的人,並把他們帶往正確的方向。
• 在徵才的時候妥協
• 不得已的雇用還可以用的人,或是只雇用幾個人,不論來的人有多好。
• 忽略表現低落的人
• 沒有事情比忽略他們…還會拖累團隊,他們會讓你最好的人才出走。
• 當你等待太久,情況已經難以回復的時候,你只能選擇讓他們離開。
• 忽略人的問題。
• 人的問題比技術的問題難多了。
• 一個純粹的技術領導人,無法滿足每一個人社交方面的需求。
• 要關心團隊的 “開心等級” - EQ

PATTERNS


• 誠實
• 讚美三明治 : 在讚美中夾著壞消息。直接提供建設性的回饋會比較好,不過要委婉並保持同理心。
• 成為一個睿智的禪學大師
• 保持冷靜,保持專注,當問題發生時,和團隊一起工作並幫助團隊討論問題。
• 大多數的時候,團隊並不是真正的想要解決問題,你需要成為探測器,幫助他們冷靜下來討論問題。
• 放開自我。
• 這不代表要失去自信,而是要拋開自大的想法,團隊知道的比你更多。
• 相信你的團隊。
• 感謝別人的詢問,不要有什麼事情是我的範圍的想法,要保持宏觀的視野。
• 如果有人問你在做什麼,可能是因為他們有興趣,而不是在挑戰你。
• 道歉。
• 要人性化,保持謙虛。
• 謙虛 != 擦腳墊。 要有自信,不要成為獨行俠。
• 弄髒自己的手
• 到現場並且作事,這樣會幫助你了解團隊的問題。
• 委派
• 請求他人幫助,不要獨攬大權
• 找方法來替代自己,讓團隊成為運作良好的機器,不需要你就可以完成任務,這是領導很好的例子。
• 給別人更多責任,然後他們就會開始自己負責。
• 做出行動:
• 如果你看到了一個問題,你希望它會消失,那忽略它是一個很誘人的選擇,但你必須跳下去並做出行動,面對這個問題。
• 保護團隊免受高層或公司的政治影響。
• 當有人搞砸,大家都知道了,就不需要在團隊面前再羞辱他們一次。和他們談談,了解發生了什麼事,在公開場合稱讚,私底下評估失敗。
• 建立共識
• 當一個老師或是導師
• 當有新人加入團隊,讓他們去犯錯,犯錯是一種選擇,只要他們不會重複犯同樣的錯。
• 設定明確的目標。
• 除非妳定義了明確的目標,不然每個人都會對要做什麼,要完成什麼有不同的意見。
• 追蹤快樂度,有一個快樂指標。
• 問別人快不快樂。
• 問別人可以為他做什麼事,或他需要你提供什麼。

總結


工程師就像植物 – 他們有不同的需要。你的工作就是找到他們需要什麼,提供給他們。
散漫-> 有目標. 無趣 -> 有熱情.

內在與外在動機


- 外在動機來自外部,內在動機是最好的一種動機,讓人們能主動的去關心。
三種最好的內在動機:
自我管理 – 讓人們自己去了解問題,並相信他們能夠解決。
專精 – 讓人有機會學習並成長,我們都希望雇用最好的人才。要雇用最好的人才,就要讓他們能不斷成長,而不是拼命去燃燒他們,叫他們只做他們擅長的事。
目標 – 給別人一個目標意識,歸屬感,讓他們有自己的意見,想法,而不是聽命行事的齒輪。

管理你的管理者


工程師要怎麼幫助管理者?以下是幫助你更好被管理的方法:
• 表現得像個成人,沒有人監督你你也可以完成工作,不要表現得像是希望有人來監督你。
• 追求責任,表現你的成長,冒可接受的風險,允許犯錯。
• 與他人溝通,讓別人知道你在想什麼。
• 指出障礙,但不要一天到晚都在指出問題
• 主張自己的意見.

3 Walkaways


• 管理者服務他人。而不是讓其他人服務你。
• 所有的Pattern都與尊重有關
• 激勵別人,而不是用鞭子與糖果
• 停止做個管理者,開始做個領導者。

問題

Q: 如果你有很好的人才, 而別人想要你的人才, 要如何鼓勵他們留下?

A: 想辦法扭轉這個情形,並專心在對你們團隊有益的事. 如果有人離開, 那不是妳的錯.

Q: 在管理自願性的專案上有什麼不同?

A: 在有薪水的環境下比較難, 自願性專案裡, 參與者是自己決定來參加的,他們有足夠的動機與興趣, 只是需要一些方向. 在公司裡,人們需要更多的內在動機.

Q: 當你的朋友要向你回報事情時,你如何處理?

A: 這可能會有點尷尬.當你需要傳達壞消息時,可能會很困難.

Q: 你如何處理你團隊成員在工作外的私人事務?

A: 以關懷與同理心處理是一個很好的界線, 如果你可以簡單的把他們換到另一個團隊, 你可以先觀察一下. 你可以和他們開誠佈公的談談這些事情.

Q: "每月最佳員工" 摧毀了團隊

A: 你也可以有”同事獎金”, 讓每個團隊成員有機會可以獎勵別人. 在團隊與個人的獎項之間,需要一些平衡.

[Translation] My Job Interview at Google

在網路上看到了My Job Interview at google這篇文章
覺得很有趣就把它翻成中文

內文如下:

我的Google面試經驗

差不多在兩個禮拜之前,我在Mountain View, California與Google的人員面試了! 這次與google的面試經驗非常的有意思,所以我想要和你們談談這次的經驗 (在發佈文章前,Google和我說了OK)

我面試的職位是Google SRE,SRE代表的是Site Reliability Engineering, Site Reliability Engineers(SREs) 同時是軟體工程師與系統管理員,負責Google服務開發到佈屬的全部過程。

總共有8次不同的面試,前三次是透過電話(電話面談)剩下的五次是實地面談,第一次面談是與招募人員,不是技術性的面談,但是剩下7次則非常的技術性

所有的面談都進行得很好,但我剛剛才知道我沒有被僱用!好吧…我個人認為進行得很好。我回答了所有問題,但看起來他們並不滿意!招募人員告訴我我的經驗不夠讓我能在一個處理緊急任務的Team工作,我應該多累積一點經驗然後再試一遍

以下是這件事發生的經過.

在我發佈了"Code Reuse in Google Chrome"這篇文章後Google的招募人員和我連繫,email上說:

我們Google正在招募最頂尖的軟體工程師.而我在有可能成為世界級工程師的名單上找到了你,
我希望能夠更瞭解妳.我也保證會提供你更多有關我們的資訊.

有興趣想要知道更多嗎?想要在Google成為一個有影響力的Player嗎?
請回覆你現在的履歷表(英文)副本,我很樂意與你連繫更多細節.


一開始我想我會申請software developer這個職位,但是我和招募人員重新檢視了我的履歷與技能,他認為我更適合SRE這個位置.我也同意他的看法.這個職位看起來像是為我量身打造的.因為我同樣的喜歡當系統管理員和設計程式。

第一次面試(電話)

第一次是在9月10日與招募人員的面試.他和我說明了Google招募人員的流程並且檢視了我的履歷與技能. 我必須給我自己的技能從0到10打分數,像是C programming, C++ programming, Python programming, 網路,演算法,資料結構,分散式系統, Linux系統管理等等…

如我之前所說,根據我的回答我們認為SRE這個位置最適合我,一個SRE基本上需要會所有事情:演算法,資料結構,程式,網路,分散式系統,大型系統架構,排除問題.這是一個很適合hacker的位置!!

在這些問題之後他問我想在哪裡工作 – Google在愛爾蘭,蘇黎世,Mountain View或是澳洲的辦公室.我回答Mountain View因為那是Googleplex(google總公司)的所在地!他回答如果面試結果OK,我會拿到讓非美國公民可以在美國工作的H-18 visa.

下半段的面試是一些基本的技術問題,只是確認我知道這些東西.問題包括了Linux系統管理,演算法,電腦架構還有C
Programming.我不能透露更多細節,因為我簽了一份保密協議而且我的招募人員很友善的要求我不要發表這些問題!

我犯了一些小錯誤,但他覺得滿意了並和我排定了第二次的電話面談時間.他警告我下次的面談會非常的技術性,我最好做好準備.我請他給我充分的時間準備,所以我們排定了下次的面試時間為9月22日.

我開始發狂般的準備.我發現了三篇有關SRE是什麼的簡報:
Engineering Reliability into Web Sites: Google SRE

Google SRE: That Couldn't Happen to US... Could It?

Google SRE: Chasing Uptime

然後我找了所有有關Google面試與面試問題的blog文章

Corey Trager's Google Interview

Rod Hilton's Google Interview

Ben Watson's Google Interview

Shaun Boyd's Google Interview

How I Blew My Google Interview by Henry Blodget

Get That Job at Google by Steve Yegge

Tales from the Google's interview room

Google Interview Questions

Google Interview Questions -- Fun Brain Teasers!

• 還有更多...


我把Google的研究報告印出來讀了一遍


The Google File System

Bigtable: A Distributed Storage System for Structured Data

MapReduce: Simplified Data Processing on Large Clusters

• 還有因為有趣而讀的Failure Trends in a Large Disk Drive Population

我也瀏覽了幾本書

• 網路基礎最好的書"TCP/IP Illustrated"

• 演算法最好的書"MIT's Introduction to Algorithms" + 我的演算法筆記

• 關於大型系統的書"Building Scalable Web Sites"

因為我不確定會不會被問到特定語言的問題,我看了一堆在C++ Cookbook, Python Cookbook, 和 Perl Cookbook的範例


第二次面試(電話)


第二次電話面試是和一個Google的工程師.他在負責AdSense與廣告的Ads team工作這次面試非常的技術性,從一個資料過大無法放入記憶體的演算法問題開始.我必須仔細的告訴他我會如何處理這個問題和我使用的資料結構與演算法,他也請我清楚的說明我的思考過程.之後他繼續問有關資料結構,DNS,TCP protocol, TCP相關的安全性問題,普遍的網路問題,還有Google本身.不過抱歉,我不能再透露更多的細節.

面試之後,那位工程師必須寫一份關於我的報告,結果是正面的-我可以繼續下一次面試.


我多給了自己一點時間來準備第三次面試,時間是十月1日.與一位Google traffic team的人面試,這次面試有一個很簡單的程式問題,然後我必須透過電話來寫程式. 可以自己選擇語言,所以我選了Perl因為那是我最喜歡的程式語言. 不過因為很難透過電話說明Perl的語法: "在這個金錢符號元素處開啟變數在資料處關閉變數開啟括號……關閉括號" 所以我透過email傳送我的Perl程式.

然後進一步討論同樣的問題,如果我們處理的資料是以Gigabyte計,以Terabyte計.我的程式/解決方法會如何改變?然後我又被問了一個有關DNS的問題,然後是HTTP protocol,routing, 和 TCP資料傳輸.

結果是正面的,我可以準備去Google面試了. 我從我的招募人員知道會有五次面試, 每次45分鐘長. 一次是我之前的工作經驗,一次是演算法和資料結構,一次是Trouble shooting和網路,然後兩次關於C與C++的軟體開發.

我的招募人員建議我讀這些文章:

Google C++ Style Guide

Web Search for a Planet: The Google Cluster Architecture

Algorithm Tutorials on TopCoder

我在十月24日下午1點從Latvia出發然後在下午八點到加州.實際上飛了14個小時,但由於我是往時差減少的方向飛,我省了7個小時.實地面試安排在十月27日,所以我可以在面試前好好休息. Google也很慷慨的幫我付了旅費,交通費與食物.我沒花任何一毛錢!


第四次面試


第四次面試終於到了GooglePlex!早上十點我與我的招募人員會面,我們花了15分鐘討論面試.他告訴我我會先有兩次面試,然後一個Google的工程師會帶我到Google的餐廳吃午飯,下午則是另外三次面試.

早上10點15,第一輪的面試開始. 是關於我之前的工作經驗. 我過去有許多工作經驗,而我決定和他們談論關於一個我幾年前以C和Linux開發的安全通報系統.這個系統會從serial port接收訊息然後送出Email與簡訊.

最後幾分鐘他問我一些基本的Unix檔案系統問題
在所有的面試中,我都可以在兩片大白板上面畫圖與寫字.真有趣!


第五次面試


第五次面試於早上11點開始.是關於coding的部分,由一個有點技巧的問題開始,但不是實際上的coding問題.我被要求以C來實做我的答案.答案是數學的演算式以及一行的Return statement.沒有大量的Coding.然後我被要求以一些知名的資料結構來實作.在coding的時候我犯了一個錯誤和忘記初始化一部分我已經malloc()了的資料!這個問題在實際開發時會產生Segfault(註:Segmentation error)然後會被找出來,但Google的工程師很重視這個問題!如果你有面試機會的話,千萬別犯任何錯誤!

這次面試結束後,我被第二次和我電話面試的Google工程師帶到餐廳吃午飯,她說她在Google工作了兩年了, 她覺得在這裡工作很快樂.我們去了一家亞洲食物的餐廳(在Google plex內),我吃了很多食物,都很好吃,而且全部免費!

然後她帶我到Googleplex內四處逛逛,非常令人讚嘆.到處都是免費的飲料與糖果,還有一些大台電玩,外面有沙灘排球場,還有很多令人驚訝的東西.


第六次面試


第六次面試開始於下午12:45.是關於Troubleshooting和網路的面試.面試者在白板上畫了一個網路圖然後想像在這裡發生了一個問題.我必須問一堆關於網路細節的問題來找出問題在哪.他很滿意並在最後幾分鐘問了我一些網路設備的細節問題.


第七次面試:


第七次面試從下午1:30開始.是coding面試.我被要求用C或C++實做一個操作String的subroutine.我選了C.不幸的是我在這裡犯了off-by-one的錯誤 – 人類歷史上最常犯的程式錯誤. 整個面試就集中在這個問題上.


第八次面試


最後,第八次面試於下午2:15開始,是關於資料結構與演算法的面試.這裡的問題和第二次面試很像.但是他的問題不只是資料大到無法放入記憶體,同時資料也是分散的.所以我必須想很多方法來解決他.這次面試的過程很自由,而我們從頭到尾討論了這個問題.我在最後找到了正確答案,他說沒有幾個面試者最後能得出這個答案的.我很高興.


面試結束後工程師帶我到大廳,幫我叫了計程車回旅館.就這樣結束了! :)


結尾:


總的來說與Google的面試過程對我來說是一種樂趣,面試的問題很技術性,但不是非常挑戰性的或困難的問題.

感謝Google提供我這次機會! :)