2

スロー クエリ ログを使用して、データベースのパフォーマンス プロファイリングを行いました。これが一番の煩わしさであることが判明しました。

UPDATE
    t1
SET
  v1t1 =
  (
    SELECT
        t2.v3t2
    FROM
        t2
    WHERE
        t2.v2t2 = t1.v2t1
    AND t2.v1t2 <= '2012-04-24'
    ORDER BY
        t2.v1t2 DESC,
        t2.v3t2 DESC
    LIMIT 1
);

サブクエリ自体はすでに遅いです。DISTINCT、GROUP BY などのサブクエリでバリエーションを試しましたが、4 秒未満では何も実行されませんでした。たとえば、次のクエリ

SELECT v2t2, v3t2
FROM t2
WHERE t2.v1t2 <= '2012-04-24'
GROUP BY v2t2
ORDER BY v1t2 DESC    

かかります:

mysql> SELECT ...
...    
69054 rows in set (5.61 sec)    

mysql> EXPLAIN SELECT ...
+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------------------------------------+
| id | select_type | table       | type | possible_keys | key  | key_len | ref  | rows    | Extra                                        |
+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------------------------------------+
|  1 | SIMPLE      | t2          | ALL  | v1t2          | NULL | NULL    | NULL | 5203965 | Using where; Using temporary; Using filesort |
+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------------------------------------+

mysql> SHOW CREATE TABLE t2;
...
  PRIMARY KEY (`v3t2`),
  KEY `v1t2_v3t2` (`v1t2`,`v3t2`),
  KEY `v1t2` (`v1t2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8  

SELECT COUNT(*) FROM t1;
+----------+
| COUNT(*) |
+----------+
|    77070 |
+----------+

SELECT COUNT(*) FROM t2;
+----------+
| COUNT(*) |
+----------+
|  5203965 |
+----------+

最新のエントリ (v3t2) とその親 (v2t2) をフェッチしようとしています。それほど大したことではないはずですよね?どのノブを回すべきかアドバイスはありますか? どんな助けやヒントも大歓迎です!

これは、より適切な SELECT ステートメントである必要があります。

SELECT
    t1.v2t1,
  (
    SELECT
        t2.v3t2
    FROM
        t2
    WHERE
        t2.v2t2 = t1.v2t1
    AND t2.v1t2 <= '2012-04-24'
    ORDER BY
        t2.v1t2 DESC,
        t2.v3t2 DESC
    LIMIT 1
) AS latest   
FROM
    t1
4

3 に答える 3

1

データベースORDER BY ... LIMIT 1にテーブルのフルスキャンを実行させて、1行のみを返すように強制しています。インデックス作成の候補として非常によく似ています。

インデックスを作成する前に、次のコマンドを実行して、フィールドの選択性を確認してください。

SELECT count(*), count(v1t2), count(DISTINCT v1t2) FROM t2;

列に多数の非NULL値があり、個別の値の数が非値の40%を超えている場合は、NULLインデックスを作成することをお勧めします。

インデックスが役に立たない場合は、列のデータを分析する必要があります。条件を使用していますt2.v1t2 <= '2012-04-24'。これは、テーブルに履歴レコードのセットがある場合、すべての行が過去のものであると予想されるため、プランナーには何も与えません。したがって、とにかくフルスキャンが最良の選択です。したがって、indexeは役に立ちません。

代わりにすべきことは、限られたレコードのサブセットのみがチェックされるようにクエリを書き直す方法を考えることです。あなたの構成は、おそらく(を含む)ORDER BY ... DESC LIMIT 1までの最新のエントリが必要であることを示しています。'2012-04-24'クエリを次のようなものに書き直してみませんか。

SELECT v2t2, v3t2
FROM t2
WHERE t2.v1t2 => date_add('2012-04-24' interval '-10' DAY)
GROUP BY v2t2
ORDER BY v1t2 DESC;

これは単なる例であり、データベースの設計とデータの性質を知ることで、より正確なクエリを構築できます。

于 2012-04-24T17:07:47.907 に答える
0

これでうまくいきますか?使用されているキーによって、並べ替えとグループの 1 つを取り除きます。

UPDATE
    t1
SET
  v1t1 =
  (
    SELECT
        MAX(t2.v3t2)
    FROM
        t2
    WHERE
        t2.v2t2 = t1.v2t1
    AND t2.v1t2 <= '2012-04-24'
    GROUP BY t2.v1t2
    ORDER BY t2.v1t2 DESC
    LIMIT 1
);

代替バージョン

UPDATE `t1`
SET `v1t1` = (
  SELECT MAX(`t2`.`v3t2`)
  FROM `t2`
  WHERE `t2`.`v2t2` = `t1`.`v2t1`
  AND `t2`.`v1t2` = (
    SELECT MAX(`t2`.`v1t2`)
    FROM `t2`
    WHERE `t2`.`v2t2` = `t1`.`v2t1
    AND `t2`.`v1t2` <= '2012-04-24'
    LIMIT 1
  )
  LIMIT 1
);

そして、このインデックスを に追加しますt2:

KEY `v2t2_v1t2` (`v2t2`, `v1t2`)
于 2012-04-24T18:23:02.287 に答える
0

サブセレクト t2 用に作成されたインデックスを見てみましょう。順序付けのために、v2t2 のインデックスと、場合によっては v1t2 と v3t2 のインデックスが必要です。インデックスは、更新クエリで結果を使用する前に、サブセレクトが結果を探す時間を短縮する必要があります。

于 2012-04-24T16:50:29.833 に答える