6

このようなクエリがあるとします...

SELECT T.TaskID, T.TaskName, TAU.AssignedUsers
FROM `tasks` T
    LEFT OUTER JOIN (
        SELECT TaskID, GROUP_CONCAT(U.FirstName, ' ',
            U.LastName SEPARATOR ', ') AS AssignedUsers
        FROM `tasks_assigned_users` TAU
            INNER JOIN `users` U ON (TAU.UserID=U.UserID)
        GROUP BY TaskID
    ) TAU ON (T.TaskID=TAU.TaskID)

特定のタスクに複数の人を割り当てることができます。このクエリの目的は、タスクごとに 1 つの行を表示することですが、タスクに割り当てられた人を 1 つの列に表示します。

さて... tasksusers、およびに適切なインデックスが設定されているとしtasks_assigned_usersます。tasks派生テーブルに結合する場合、MySQL オプティマイザーは引き続き TaskID インデックスを使用しません。なんと!?!?

それで、私の質問は...どうすればこのクエリでtasks_assigned_users.TaskIDのインデックスを使用できるでしょうか? 一時テーブルは不十分なので、それが唯一の解決策である場合... MySQL オプティマイザーはばかげています。

使用されるインデックス:

  • タスク
    • プライマリ - タスク ID
  • ユーザー
    • プライマリ - ユーザー ID
  • tasks_assigned_users
    • プライマリ - (タスク ID、ユーザー ID)
    • 追加インデックス UNIQUE - (UserID,TaskID)

編集:また、このページには、結合が発生する前に派生テーブルが実行/マテリアライズされると書かれています。キーを再利用して結合を実行してみませんか?

編集 2: MySQL オプティマイザーでは、派生テーブルにインデックス ヒントを配置できません(おそらく、派生テーブルにインデックスがないため)

編集 3:これは、これに関する本当に素晴らしいブログ投稿です: http://venublog.com/2010/03/06/how-to-improve-subqueries-derived-tables-performance/ ケース #2 が解決策であることに注意してください。を探していますが、現時点では MySQL はこれをサポートしていないようです。:(

編集 4:ちょうどこれを見つけた:「MySQL 5.6.3 の時点で、オプティマイザーは FROM 句 (つまり、派生テーブル) のサブクエリをより効率的に処理します:...クエリの実行中に、オプティマイザーは派生テーブルにインデックスを追加する場合があります。そこからの行の取得を高速化します。」有望そうです...

4

3 に答える 3

4

MySQL Server 5.6には、これに対する解決策があります-プレビューリリース(この記事の執筆時点)。

http://dev.mysql.com/doc/refman/5.6/en/from-clause-subquery-optimization.html

ただし、MySQL Optimizerが「派生テーブルにインデックスを追加する」ときに、既存のインデックスを再利用するかどうかはわかりません。

次のクエリについて考えてみます。

SELECT * FROM t1 JOIN(SELECT * FROM t2)AS Delivered_t2 ON t1.f1 = defined_t2.f1;

ドキュメントには次のように書かれています。「オプティマイザーは、derived_t2から列f1にインデックスを作成します。そうすることで、最低コストの実行プランでrefアクセスを使用できるようになります。」

OK、それは素晴らしいことですが、オプティマイザーはt2からのインデックスを再利用しますか?つまり、t2.f1にインデックスが存在する場合はどうなるでしょうか。このインデックスは再利用されますか、それともオプティマイザは派生テーブルに対してこのインデックスを再作成しますか?知るか?

編集: MySQL 5.6までの最善の解決策は、一時テーブルを作成し、そのテーブルにインデックスを作成してから、一時テーブルに対してSELECTクエリを実行することです。

于 2012-01-18T20:22:33.703 に答える
2

私が見る問題は、サブクエリを実行すると、基になるインデックス付きテーブルがないことです。あなたがパフォーマンスをしているなら、私は最後に次のようなグループ化を行います:

SELECT T.TaskID, T.TaskName, GROUP_CONCAT(U.FirstName, ' ', U.LastName SEPARATOR ', ') AS AssignedUsers
FROM `tasks` T
    LEFT OUTER JOIN  `tasks_assigned_users` TAU ON (T.TaskID=TAU.TaskID)
    INNER JOIN `users` U ON (TAU.UserID=U.UserID)
GROUP BY T.TaskID, T.TaskName
于 2012-01-18T19:44:16.517 に答える
1

申し訳ありませんが、それは不可能です。インデックスを使用するには、一時テーブルまたはビューを作成する必要があります。

于 2012-01-18T19:32:11.577 に答える