-1

重複の可能性:
区切られたリストをデータベース列に格納するのは本当に悪いことですか?

私は、すべての関係がコンマ区切りの文字列として保存されるいくつかの PHP/MySQL プロジェクトに取り組んできました。

たとえば、共通の関係は次のようになります

(疑似コードで)

table people
id - integer
name - string
age - integer
teams - string (CSV OF integers, ex '1,3,9,21')

table teams
name - String
id - integer

人間関係の管理が面倒になります。

個人のすべてのチームを取得するには:

$person = 'SELECT * FROM People WHERE id= x';

次に、phpで次のようなことをしています

$person['teams'] = SELECT * FROM teams WHERE id IN ($person['teams']);

これを書いているときに、おそらく次のような mysql クエリでそれらを組み合わせることができることに気付きました。

SELECT 
  people.id, 
  people.name, 
  people.teams, 
  teams.name 
FROM people 
JOIN teams ON FIND_IN_SET(teams.id, people.teams) WHERE people.id=x

このタイプのセットアップではFIND_IN_SET、かなり頻繁にを使用しています。

最後に、私の質問は次のとおりです。このような関係を作成すると、パフォーマンス上の利点はありますか?

これまでの私の経験では、通常、FIND_IN_SET は完全なテーブル スキャンを実行していました。パフォーマンス上の利点がない場合、カンマ区切りの整数リストを使用する利点があるのはどのような場合ですか? FIND_IN_SET を作成するときに、mysql の設計者は何かを念頭に置いていたようです。

4

2 に答える 2

6

そうです、FIND_IN_SET()はインデックスを利用できないため、全表スキャンが発生します。技術的には、その関数はリレーショナルデータベースの偽の操作ですが、それに対する需要が多かったことは間違いないので、MySQLがそれを実装しました。

カンマ区切りのリストにデータを格納することは、非正規化の例です。正規化された設計から逸脱すると、1つのタイプのクエリのパフォーマンスが向上しますが、通常、同じデータに対する他のすべてのタイプのクエリが犠牲になります

たとえば、プレーヤーとそのチームをコンマ区切りのリストとして保存すると、参加しなくても、特定のプレーヤーのチームのリストを非常に簡単に取得できます。これはパフォーマンスの向上です。ただし、特定のプレーヤーのチームの詳細を取得することははるかに困難です。同様に、特定のチームのすべてのプレーヤーを検索します。

カンマ区切りのリストは、そのリストが個別の「ブラックボックス」データとして扱われる場合にのみ使用してください。つまり、アプリケーションはそのリストをアイテム全体としてフェッチする必要がありますが、リストのサブセットをフェッチする必要はありません。また、検索、結合、並べ替え、小計などにリスト内の要素を使用するためにSQLを記述する必要はありません。

データベース列に区切りリストを格納することは本当に悪いですか?に対する私の答えも参照してください。

于 2013-01-22T20:13:04.570 に答える
3

テーブル スキャンは、いつでもメリットと見なすことはできません。

さらに、私が学校から覚えている限り、それは通常の形式 ( http://en.wikipedia.org/wiki/Database_normalization ) を破っています。

パフォーマンスを向上させるために、すべての主キー/外部キー列にインデックスを付けることをお勧めします。

そのような状況で私が持つ唯一のアイデアは、特定のプロジェクトのアーキテクトに、ソリューションの背後にある彼のアイデアは何かを丁寧に尋ね、この背後にあるパフォーマンスの惨事について彼/彼女に説明することです:)

于 2013-01-22T20:06:48.653 に答える