GoogleがBigQueryテーブルを保存する方法とそれがユーザーに与える影響

公開: 2016-02-24

これは私たちのブログの技術トークインスタレーションであり、開発者の並外れたアダムノックスによってもたらされました。

Big QueryはSQLと非常によく似た構文を使用しますが、実際には、大量のデータを処理するためのソリューションとは大きく異なるタクトが必要です。 Big Queryはブルートフォース攻撃を行う傾向があり、実際にはインデックスを使用しないため、大量のデータは大量のプロセッサと処理時間を意味します。 これを実現するために、Googleは、クエリの設計方法に影響を与える可能性のあるデータを保存する別の方法を採用しました。

ファイル形式

テーブルが作成されると、GoogleはColumnIO形式を使用してデータを保存します。 繰り返されるフィールドを除いて、各列は個別のファイルとして保存されます。 次の列を持つテーブルがある場合:name(文字列)、phoneNumbers(繰り返される整数); 名前は他の名前と一緒に1行に保存され、その名前に関連付けられているすべての電話番号は電話番号と一緒に1行に保存されます。 列が大きくなりすぎると、列が分割されることもありますが、ワークフローに影響はありません。

これを知っていると、実際には気にしない列を処理しないことで、より高速なクエリを実行できます。場合によっては、以前はクエリを実行できなかった可能性もあります。 システムは処理されたデータの量に応じて課金されるため、クエリも安くなる可能性があります。列がクエリに含まれていない場合、そのデータは処理されません。

ファイルストレージ

テーブルを作成した場合、ファイルが作成されると、3つの異なるデータセンター、さらには各データセンター内の3つの異なる場所に保存されるため、どこにも行かないのでかなり安全だと感じることができます。 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"))

それぞれ整数を含む2つの列のみが使用されるため、これはまだかなり安価なクエリ($ 0.0003)ですが、以下のクエリでは28+にアクセスしていると言われていますが、1.857TBであり、 。

 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は、新しい行をテーブルにストリーミングできるため、変更のログ記録と変更の分析に最適です。 ただし、インデックスがないため、特定の行をすばやく頻繁に検索するためのひどいデータストレージデバイスです。また、テーブル内の行を変更または削除できないため、変更が予想されるオブジェクトの単一の表現を保存する場合にも適していません。 。

テーブルの分割

状況によっては、単一の列にアクセスするだけでも、BigQueryで処理するには多すぎます。 リストの作成日の順序でリストIDを返す次の使用できないクエリを提示します。

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

技術的には、これが成功することは最近可能になりましたが、より高い請求階層を有効にする必要があるため、Vendastaの人々は成功しませんでした。 事前に注文されたインデックスがないため、少量のデータを非常に集中的に処理しているため、この場合は処理に対して課金されます。 請求階層の変更は、Big Query UIのインタラクティブクエリで、[オプション]ボタンの下の[無制限に許可](有効になっている場合)をオンにすることで実行できます。

クエリが可能な限り効率的であると仮定すると、これらの種類の厳しい制限を回避するためにテーブルサイズを削減するためのいくつかのアプローチが残っています。 1つはテーブルタイムデコレータで、2つ目はハッシュを使用します。

テーブルデコレータについて詳しくは、こちらをご覧ください。 LIMIT/WHERE/HAVING/OMITなどのコマンドを使用して結果をフィルタリングするのとは異なり、テーブルデコレータは、指定された範囲外のデータにもアクセスしないため、テーブルのクエリのコストを実際に削減します。 残念ながら、このメソッドはVendastaではほとんど役に立たないため、実際にストリーミングするListingHistoryModelのようなテーブルでも、テーブル全体を削除し、NDBからの場合は毎日レプリカに置き換えます。つまり、テーブル時間デコレータは当日のエントリのみを気にする場合は、ListingHistoryModel。

ロギングを見るのは、Vendastaで非常に役立つ1つの場所です。 実際のログコンテンツのサイズが原因で、計算とメモリの制限に簡単に到達でき、ログコンテンツの列だけでもクエリを実行するとコストがかかります。 ログの場合、通常は特定の時点のみを気にします。これはまさにタイムデコレータが役立つものです。

クエリ結果

クエリを実行するたびに、新しいテーブルが作成され、場合によっては、バックグラウンドで不明な非表示のテーブルが作成されます。 そのように選択した場合は、結果テーブルに名前を付けて保持するか、Googleが付けた名前のままにして、1日後に消えるようにすることができます。 「応答が大きすぎて返せない」という事態に遭遇した場合、それは彼らがあなたをあなた自身から保護しているからです。 巨大なテーブルを作成するのは簡単です(特にクロス結合を使用)。 これが発生し、それが発生することを期待していた場合は、テーブルに名前を付けて、[大きな結果を許可する]オプションを有効にする必要があります。 新しい行がストリーミングされていないクエリを繰り返すと、キャッシュされた結果がまだ存在する場合にのみ取得されます。