Programmingフルスタック開発者

SQLでの配列や配列の類似物を使用して、1つのセルに複数の値を格納および分析する方法と、そのアプローチが正当化されるのはいつか?

Hintsage AIアシスタントで面接を突破

回答。

質問の背景

従来のSQLは、1つのセルに複数の値を格納することを想定していません。リレーショナルモデルは正規化を要求します。しかし、現代の問題では「タグリスト」や「評価スケール」などのフィールドが頻繁に見られ、特定の行のレベルで複数の値を操作することが便利です。一部のDBMS(PostgreSQL、Oracle)は、ARRAY型や類似のメカニズムを提供しています。

問題

配列を使用することは、正規化の原則に違反し、多くの操作(フィルタリング、更新、インデックス作成)を困難にし、DBMS間でのコードの移植性を低下させます。しかし、キャッシュや小さな値リストの高速検索などの理由で便利または避けられない場合があります。

解決策

  • PostgreSQLでは、配列サポートがネイティブです。例:
CREATE TABLE products ( id SERIAL PRIMARY KEY, tags TEXT[] ); -- 挿入: INSERT INTO products(tags) VALUES (ARRAY['eco','sale','hot']); -- 配列を基に検索: SELECT * FROM products WHERE 'eco' = ANY (tags);
  • MySQL 5.xには配列がなく、JSONや区切り文字列、解析関数がよく使用されます。
  • Oracleでは、コレクション、ネストされたテーブル/バリアッド。
  • 最適な分析タスクには、正規化(product_tagsという関連した二次テーブルを作成)を行い、JOINを使用し、配列は特別な場合(パフォーマンスや特定の要件)にのみ保持します。

主な特徴:

  • 配列が本当に必要であり、DBMSがこれをサポートしている場合は便利です。
  • 大きな配列の場合、インデックスとフィルタリングに問題が生じます。
  • DBMS間での移植性がなく、サポートが難しくなります。

トリックのある質問。

配列の個々の要素にインデックスを付けることはできますか?

PostgreSQLでは、はい、GIN/GISTインデックスを通じて可能です:

CREATE INDEX idx_tags ON products USING GIN (tags);

区切り文字で文字列列の配列内の値の存在を迅速に確認するにはどうすればよいですか?

SQLは標準でできませんが、パターン検索を使用します:

SELECT * FROM users WHERE ',admin,' like concat('%,',role,',%');

しかし、このアプローチは信頼性が低く、遅いです。

配列にどれだけの値を格納でき、何が制限していますか?

制限はDBMSによります。例えば、PostgreSQLでは文字列のサイズ(1〜2 MB)のみ制限があります。

一般的なエラーとアンチパターン

  • "簡単さ"のために1つのセルに配列を保存し、分析を困難にする
  • 区切り文字を考慮せずにLIKEで値を誤ってフィルタリングする
  • 配列の行に基づいて一意性とインデックスを行うことに依存する

実生活の例

ネガティブケース

eコマースプロジェクトで商品タグをカンマ区切りの文字列として1つの列に保存することにしました。タグによる商品の迅速な検索が非常に困難になり、フィルタリングのエラーが発生し、解析エラーのためにタグの重複が発生しました。

利点:

  • "簡単"で迅速に実装可能

欠点:

  • 規模が大きくなると非常に遅くなる、サポートが困難、一意性の保証が不可能

ポジティブケース

PostgreSQLでは、小さくて変更されないセット(ユーザーロール)にARRAYとGINインデックスを使用しました。大きい場合は、ロール用の別のテーブルを使用しました。

利点:

  • インデックスを介したARRAYの迅速な検索
  • 必要な場合、リレーショナルモデルとの互換性を維持

欠点:

  • 移植性がなく、DBMSの拡張した特性に関する知識が必要