1

私は Postgres のバックグラウンドから来て、アプリケーションを MySQL に変換しようとしています。Postgres では非常に高速で、MySQL では非常に遅いクエリがあります。いくつかの分析を行った後、劇的な速度の違いの原因の 1 つはネストされたクエリであると判断しました。次の擬似クエリは、Postgres で 170 ミリ秒、MySQL で 5.5 秒かかります。

SELECT * FROM (
  SELECT id FROM a INNER JOIN b
) AS first LIMIT 10

MySQL と Postgres の両方で、次のクエリの速度は同じです (10 ミリ秒未満)。

SELECT id FROM a INNER JOIN b LIMIT 10

私は両方のデータベースにまったく同じテーブル、インデックス、およびデータを持っているので、なぜこれが遅いのか本当にわかりません。

どんな洞察も大歓迎です。

ありがとう

編集

なぜ私がこれを行う必要があるのか​​ の具体的な例を次に示します。最大の合計を取得する必要があります。これを行うには、以下のクエリに示すようにサブ選択が必要です。

SELECT SUM(a) AS a
  FROM (
    SELECT table2.b, MAX(table1.a) AS a
    FROM table1
    INNER JOIN table2 ON table2.abc_id = table1.abc_id
      AND table1.read_datetime >= table2.issuance_datetime
      AND table1.read_datetime < COALESCE(table2.unassignment_datetime, DATE('9999-01-01'))
    WHERE table1.read_datetime BETWEEN '2012-01-01 10:30:01' AND '2013-07-18 03:03:42' AND table2.c = 0
    GROUP BY table2.id, b
) AS first
GROUP BY b
LIMIT 10

このクエリも、MySQL では 14 秒、Postgres では 238 ミリ秒かかります。MySQL の Explain からの出力は次のとおりです。

id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra
1,PRIMARY,<derived2>,ALL,\N,\N,\N,\N,25584,Using temporary; Using filesort
2,DERIVED,table2,index,PRIMARY,index_table2_on_b,index_table2_on_d,index_table2_on_issuance_datetime,index_table2_on_unassignment_datetime,index_table2_on_e,PRIMARY,4,\N,25584,Using where
2,DERIVED,tz,ref,index_table1_on_d,index_table1_on_read_datetime,index_table1_on_d_and_read_datetime,index_table1_on_4,4,db.table2.dosimeter_id,1,Using where
4

4 に答える 4

2

ジョン、あなたのコメントに答えて、ここに例があります:

drop table if exists temp_preliminary_table;
create temporary table temp_preliminary_table
    SELECT table2.b, MAX(table1.a) AS a
    FROM table1
    INNER JOIN table2 ON table2.abc_id = table1.abc_id
      AND table1.read_datetime >= table2.issuance_datetime
      AND table1.read_datetime < COALESCE(table2.unassignment_datetime, DATE('9999-01-01'))
    WHERE table1.read_datetime BETWEEN '2012-01-01 10:30:01' AND '2013-07-18 03:03:42' AND table2.c = 0
    GROUP BY table2.id, b;
-- I suggest you add indexes to this temp table
alter table temp_preliminary_table
    add index idx_b(b); -- Add as many indexes as you need
-- Now perform your query on this temp_table
SELECT SUM(a) AS a
FROM temp_preliminary_table
GROUP BY b
LIMIT 10;

これは単なる例であり、クエリを 3 つのステップに分割しています。

MySQL の一時テーブルはそれらを作成した接続にのみ表示されるため、他の接続では (良くも悪くも) 別の接続によって作成された一時テーブルが表示されないことを覚えておく必要があります。

この「分割統治」アプローチにより、多くの頭痛の種が解消されました。お役に立てば幸いです。

于 2013-07-23T20:42:57.103 に答える