Google 如何存儲您的大查詢表以及它如何影響您

已發表: 2016-02-24

這是我們博客的技術講座安裝,由非凡的開發人員 Adam Knox 帶給您。

儘管 Big Query 使用的語法與 SQL 非常相似,但它實際上與處理大量數據的解決方案有很大不同。 Big Query 傾向於暴力破解,實際上並不使用索引,因此大量數據意味著大量處理器和處理時間。 為了實現這一目標,Google 採用了一種不同的數據存儲方式,這可能會影響您設計查詢的方式。

文件格式

創建表後,Google 會使用其 ColumnIO 格式來存儲您的數據。 每列都存儲為一個單獨的文件,但重複字段除外。 如果您有一個包含列的表:名稱(字符串),電話號碼(重複整數); 該名稱將與其他名稱存儲在同一行中,並且與該名稱關聯的所有電話號碼將與電話號碼一起存儲在同一行中。 如果列太大,也可以拆分列,但這不會影響工作流程。

知道這一點可以通過不處理您實際上不關心的列來運行更快的查詢,並且在某些情況下甚至可以使以前無法運行查詢成為可能。 查詢也可能變得更便宜,因為系統按處理的數據量收費,如果查詢中不包含列,則不會處理該數據。

文件存儲

如果您創建了一個表,您會感到相當安全,因為一旦創建了文件,它們就會存儲在三個不同的數據中心,甚至每個數據中心內的三個不同位置。 由於 Big Query 會給處理器帶來問題,因此數據需要易於訪問。 對此的警告是臨時數據集。 有一個選項可以為數據集中的表格指定到期時間,一旦表格超過此到期日期,表格就會消失。

表層次結構

一個項目可以存儲數據集,每個數據集都可以包含表。 在 Big Query 語法中訪問表的完整命令是[projectname:datasetname.tablename] ,但是如果您從當前正在處理的項目中訪問表,則可以將其縮短為dataset.tablename

將相關數據分解到單獨的表中(例如:按日期或在特定事件發生後)有助於進行更易於維護的查詢,因為查詢通常會在表中的所有行上運行。 這意味著您可能想要查看多個表,因此每個數據集中隱藏了一個稱為元表的東西,可以在[projectname:datasetname.__TABLES__]訪問它,它包含有關數據集中每個表的信息,可用於聚合表查詢。

命令TABLE_QUERY是一個命令,它允許在對聚合運行查詢之前聚合多個相似的表,並且__TABLES__中的任何列都可以用來形成這個聚合。 例如,如果我想了解自 2016 年 1 月 1 日以來某個項目的響應時間,我可以運行以下查詢來顯示最小、中值和最大響應時間:

 SELECT QUANTILES((protoPayload.endTime - protoPayload.startTime), 3) AS responseTimeBucketsInMilliseconds FROM (TABLE_QUERY(appengine_logs, "table_id CONTAINS 'appengine_googleapis_com_request_log' AND creation_time > 1451606400000"))

由於只使用了兩列,每列都包含整數,這仍然是一個相當便宜的查詢(0.0003 美元),即使它正在訪問 28+,我被下面的查詢告訴我是 1.857TB,訪問每個字段大約需要 9 美元.

 SELECT SUM(size_bytes)/1000000000 FROM [repcore-prod:appengine_logs.__TABLES__] WHERE table_id CONTAINS 'appengine_googleapis_com_request_log' AND creation_time > 1451606400000

更新文件

Big Query 在記錄更改和分析所述更改方面非常出色,因為您可以將新行流式傳輸到表中。 但是,由於缺少索引,它是一種糟糕的數據存儲設備,用於快速和頻繁地查找特定行,並且由於無法修改或刪除表中的行而無法存儲您希望更改的對象的單一表示形式。 .

分錶

在某些情況下,即使訪問單個列在 Big Query 中也難以處理。 我向您展示以下不可用的查詢,該查詢按列表創建日期的順序返回列表 ID:

 SELECT lid FROM [repcore-prod:datastore.LIS] ORDER BY ct

從技術上講,最近它有可能成功,但對於 Vendasta 的人來說卻不是,因為它需要啟用更高的計費層。 由於沒有預先排序的索引,它會非常密集地處理少量數據,因此在這種情況下,它們會為處理收費。 可以在 Big Query UI 的交互式查詢中更改計費層級,方法是選中“選項”按鈕下的“允許無限制”(如果啟用)。

假設您的查詢盡可能高效,有幾種方法可以減少表大小以繞過這些硬限制。 第一個是表時間裝飾器,第二個是散列。

您可以在此處了解有關餐桌裝飾器的更多信息。 與使用LIMIT/WHERE/HAVING/OMIT之類的命令過濾結果不同,表裝飾器實際上會降低查詢表的成本,因為它甚至不會訪問給定範圍之外的數據。 不幸的是,這種方法在 Vendasta 幾乎沒用,因為即使對於我們實際流式傳輸到的像 ListingHistoryModel 這樣的表,如果它來自 NDB,我們仍然會刪除整個表並每天用一個副本替換它,這意味著表時間裝飾器只能在如果您只關心當天的條目,ListingHistoryModel。

查看日誌記錄是他們對 Vendasta 很有幫助的一個地方。 由於實際日誌內容的大小,很容易達到計算和內存限制,即使只是查詢日誌內容列也很昂貴。 對於日誌,通常人們也只關心特定的時間點,而這正是時間裝飾器所幫助的。

查詢結果

每次運行查詢時,它都會創建一個新表,有時還會在後台創建未知的隱藏表。 如果你這樣選擇,那麼你可以給結果表一個名字來保留它,或者讓它保持 google 給它的名字,讓它在一天后消失。 如果您遇到“響應太大而無法返回”,那是因為他們正在保護您免受自己的傷害。 創建巨大的表很容易(尤其是交叉連接)。 如果發生這種情況並且您期望它會發生,那麼您需要為表命名並啟用“允許大結果”選項。 如果您重複一個沒有新行流式傳輸的查詢,那麼如果它們仍然存在,您將只會獲得緩存的結果。