0

奇妙なことに、私は mySQL で多くの開発を行ってきましたが、今日遭遇したもののいくつかに遭遇したことはありません。

だから、私は user_items テーブルを持っています

ID | name
---------
1  | test

それから item_data テーブルがあります

ID | item | added | info
-------------------------
1  | test | 12345 | important info
2  | test | 23456 | more recent important info

次に、メールテーブルがあります

ID | added | email
1  | 12345 | old@b.com
2  | 23456 | a@b.com
3  | 23456 | b@c.com

および email_verified テーブル

ID | email
-----------
1  | a@b.com

これらのテーブルのセットアップが効率的でないなどの可能性があることは理解していますが、これは変更できず、見た目よりもはるかに複雑です。

私がやりたいことは次のとおりです。ユーザーのアイテムを検索し、関連する情報と関連する電子メールを表示したり、電子メールが検証されたかどうかを表示したりしたいと考えています。

user_items.name = item_data.item
item_data.added = emails.added
emails.email = emails_verified.email

したがって、ユーザー アイテム 1 については、テストします。ID、名前、最新の情報、最新の電子メール、およびそれらの検証ステータスを返すことができるようにしたいと考えています。

だから私は戻りたい

ID => 1
name => test
information => more recent important info
emails => array('0' => array('email' => 'a@b.com' , 'verified' => 'YES'),'1' => array('email' => 'b@c.com' , 'verified' => 'NO'))

これで、複数のクエリを使用して比較的簡単にこれを行うことができます。ただし、私の調査では、大量の結合ステートメントを含む 1 つの (非常に複雑ではありますが) mysql クエリを使用する場合よりも、リソース/時間のコストが大幅にかかることが示唆されています。

1 つのクエリを使用すると便利な理由も (私は信じています)、比較的簡単に検索機能を追加できるためです。複雑な where ステートメントをクエリに追加します。

さらに複雑なことに、私は CodeIgniter を使用しています。私はあまりにもうるさいことはできません:)したがって、CIの回答がない場合でも非常に役立ちます。

これまでに取得したコードは次のとおりです。しかし、それは非常に「私が何をしているのかよくわかりません」です。

function test_search()
{
    $this->load->database();
    $this->db->select('user_items.*,item_data.*');
    $this->db->select('GROUP_CONCAT( emails.email SEPARATOR "," ) AS emails', FALSE);
    $this->db->select('GROUP_CONCAT( IF(emailed.email,"YES","NO") SEPARATOR "," ) AS emailed', FALSE);

    $this->db->where('user_items.name','test');
    $this->db->join('item_data','user_items.name = item_data.name','LEFT');
    $this->db->join('emails','item_data.added = emails.added','LEFT');
    $this->db->join('emailed','emails.email = emailed.email','LEFT');
    $this->db->group_by('user_items.name');
    $res = $this->db->get('user_items');

    print_r($res->result_array());
}

これについて何か助けていただければ幸いです。

これは本当に複雑な SQL です。これは本当にこの機能を実現する最善の方法ですか?

ありがとう

アップデート

Cryodeの優れた回答に続きます。

唯一の問題は、1 つのメールしか返さないことです。ただし、GROUP_CONCAT を使用することで、すべてのメールとすべての email_verified ステータスを取得して、PHP で展開できる文字列にすることができました。

明確にするために、サブクエリは、

SELECT item, MAX(added) AS added
            FROM item_data
            GROUP BY item

基本的に一時テーブルを作成しますか?

ここで概説したものと同様

確かに、item_data から 1 つの行 (最新の行) のみを取得するためにサブクエリが必要ですか?

そして最後に、設計が不十分なデータベースに関するメモに答えます。

item_data は定期的に変更されるため、データベースはこのように設計されていますが、履歴レコードを保持したいと考えています。

メールはアイテム データの一部ですが、メールの数に制限はなく、メールを検索できるようにするため、個別のテーブルを選択しました。そうしないと、メールを item_data テーブル内でシリアル化する必要があります。

電子メールは複数のアイテムに関連付けることができるため、emails_verified テーブルは別のものです。

それを考えると、クエリは(明らかに)複雑ですが、それでも適切な設定のようです..?

ありがとう

最終更新

Cryodes の回答は、データベース アーキテクチャ全般に関連する非常に役立つ回答です。

これをもう少し概念化すると、バージョン ID を user_items に格納する場合、サブクエリは必要ありません。

バージョン間のデータは必ずしも一貫していないため、彼の提案された項目テーブルを破棄します (この場合)。次に、item_data テーブルから正しいバージョンを取得できます。また、バージョン ID に基づいて items_version_emails 行を取得し、これから「emails」テーブルからそれぞれのメールを取得できます。

IE それは完全に動作します。

これの欠点は、新しいバージョンのデータを item_data に追加するときに、挿入された新しいバージョンで user_items テーブルを更新する必要があることです。

これは問題ありませんが、単純に一般化された点として、何がより速いのでしょうか? このようなセットアップが提案された理由は、それがより速いからだと思います.新しいデータが追加されるたびに余分な更新を行うことは、多くの行が表示されているときに潜在的に数百のサブクエリを節約する価値があります. 特に、データを更新するよりも表示することを考えると。

将来データベース アーキテクチャを設計するときの知識として、何がより高速で、なぜ私たち全員がより最適化されたデータベースを作成できるのかについて、リンク/一般的なガイダンスを持っている人はいますか。

Cryodeに再び感謝します!!

4

1 に答える 1