mysql - 見方 - sql 遅い 原因




どのようにこのMySQLのクエリを最適化するには? 数百万行 (9)

あなたの質問に見つかった問題のみ

GROUP BY analytics.source 
ORDER BY frequency DESC 

この問合せのために一時表を使用してfilesortを実行しています。

これを回避する1つの方法は、次のような別のテーブルを作成することです

CREATE TABLE `analytics_aggr` (
  `source` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `frequency` int(10) DEFAULT NULL,
  `sales` int(10) DEFAULT NULL,
  KEY `sales` (`sales`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`

以下のクエリを使用してanalytics_aggrにデータを挿入する

insert into analytics_aggr SELECT 
    analytics.source AS referrer, 
    COUNT(analytics.id) AS frequency, 
    SUM(IF(transactions.status = 'COMPLETED', 1, 0)) AS sales
    FROM analytics
    LEFT JOIN transactions ON analytics.id = transactions.analytics
    WHERE analytics.user_id = 52094 
    GROUP BY analytics.source 
    ORDER BY null 

これで簡単にデータを取得できます

select * from analytics_aggr order by sales desc

私は次のクエリを持っています:

SELECT 
    analytics.source AS referrer, 
    COUNT(analytics.id) AS frequency, 
    SUM(IF(transactions.status = 'COMPLETED', 1, 0)) AS sales
FROM analytics
LEFT JOIN transactions ON analytics.id = transactions.analytics
WHERE analytics.user_id = 52094 
GROUP BY analytics.source 
ORDER BY frequency DESC 
LIMIT 10 

分析表には60Mの行があり、トランザクション表には3Mの行があります。

このクエリでEXPLAINを実行すると、次のようになります。

+------+--------------+-----------------+--------+---------------------+-------------------+----------------------+---------------------------+----------+-----------+-------------------------------------------------+
| # id |  select_type |      table      |  type  |    possible_keys    |        key        |        key_len       |            ref            |   rows   |   Extra   |                                                 |
+------+--------------+-----------------+--------+---------------------+-------------------+----------------------+---------------------------+----------+-----------+-------------------------------------------------+
| '1'  |  'SIMPLE'    |  'analytics'    |  'ref' |  'analytics_user_id | analytics_source' |  'analytics_user_id' |  '5'                      |  'const' |  '337662' |  'Using where; Using temporary; Using filesort' |
| '1'  |  'SIMPLE'    |  'transactions' |  'ref' |  'tran_analytics'   |  'tran_analytics' |  '5'                 |  'dijishop2.analytics.id' |  '1'     |  NULL     |                                                 |
+------+--------------+-----------------+--------+---------------------+-------------------+----------------------+---------------------------+----------+-----------+-------------------------------------------------+

すでに非常に基本的なので、このクエリを最適化する方法を理解できません。 このクエリを実行するのに約70秒かかります。

存在するインデックスは次のとおりです。

+-------------+-------------+----------------------------+---------------+------------------+------------+--------------+-----------+---------+--------+-------------+----------+----------------+
|   # Table   |  Non_unique |          Key_name          |  Seq_in_index |    Column_name   |  Collation |  Cardinality |  Sub_part |  Packed |  Null  |  Index_type |  Comment |  Index_comment |
+-------------+-------------+----------------------------+---------------+------------------+------------+--------------+-----------+---------+--------+-------------+----------+----------------+
| 'analytics' |  '0'        |  'PRIMARY'                 |  '1'          |  'id'            |  'A'       |  '56934235'  |  NULL     |  NULL   |  ''    |  'BTREE'    |  ''      |  ''            |
| 'analytics' |  '1'        |  'analytics_user_id'       |  '1'          |  'user_id'       |  'A'       |  '130583'    |  NULL     |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
| 'analytics' |  '1'        |  'analytics_product_id'    |  '1'          |  'product_id'    |  'A'       |  '490812'    |  NULL     |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
| 'analytics' |  '1'        |  'analytics_affil_user_id' |  '1'          |  'affil_user_id' |  'A'       |  '55222'     |  NULL     |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
| 'analytics' |  '1'        |  'analytics_source'        |  '1'          |  'source'        |  'A'       |  '24604'     |  NULL     |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
| 'analytics' |  '1'        |  'analytics_country_name'  |  '1'          |  'country_name'  |  'A'       |  '39510'     |  NULL     |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
| 'analytics' |  '1'        |  'analytics_gordon'        |  '1'          |  'id'            |  'A'       |  '56934235'  |  NULL     |  NULL   |  ''    |  'BTREE'    |  ''      |  ''            |
| 'analytics' |  '1'        |  'analytics_gordon'        |  '2'          |  'user_id'       |  'A'       |  '56934235'  |  NULL     |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
| 'analytics' |  '1'        |  'analytics_gordon'        |  '3'          |  'source'        |  'A'       |  '56934235'  |  NULL     |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
+-------------+-------------+----------------------------+---------------+------------------+------------+--------------+-----------+---------+--------+-------------+----------+----------------+


+----------------+-------------+-------------------+---------------+-------------------+------------+--------------+-----------+---------+--------+-------------+----------+----------------+
|    # Table     |  Non_unique |      Key_name     |  Seq_in_index |    Column_name    |  Collation |  Cardinality |  Sub_part |  Packed |  Null  |  Index_type |  Comment |  Index_comment |
+----------------+-------------+-------------------+---------------+-------------------+------------+--------------+-----------+---------+--------+-------------+----------+----------------+
| 'transactions' |  '0'        |  'PRIMARY'        |  '1'          |  'id'             |  'A'       |  '2436151'   |  NULL     |  NULL   |  ''    |  'BTREE'    |  ''      |  ''            |
| 'transactions' |  '1'        |  'tran_user_id'   |  '1'          |  'user_id'        |  'A'       |  '56654'     |  NULL     |  NULL   |  ''    |  'BTREE'    |  ''      |  ''            |
| 'transactions' |  '1'        |  'transaction_id' |  '1'          |  'transaction_id' |  'A'       |  '2436151'   |  '191'    |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
| 'transactions' |  '1'        |  'tran_analytics' |  '1'          |  'analytics'      |  'A'       |  '2436151'   |  NULL     |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
| 'transactions' |  '1'        |  'tran_status'    |  '1'          |  'status'         |  'A'       |  '22'        |  NULL     |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
| 'transactions' |  '1'        |  'gordon_trans'   |  '1'          |  'status'         |  'A'       |  '22'        |  NULL     |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
| 'transactions' |  '1'        |  'gordon_trans'   |  '2'          |  'analytics'      |  'A'       |  '2436151'   |  NULL     |  NULL   |  'YES' |  'BTREE'    |  ''      |  ''            |
+----------------+-------------+-------------------+---------------+-------------------+------------+--------------+-----------+---------+--------+-------------+----------+----------------+

状況を改善しなかったので、提案されたように追加のインデックスを追加する前に、2つのテーブルのスキーマを簡素化しました。

CREATE TABLE `analytics` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `affil_user_id` int(11) DEFAULT NULL,
  `product_id` int(11) DEFAULT NULL,
  `medium` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `source` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `terms` varchar(1024) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `is_browser` tinyint(1) DEFAULT NULL,
  `is_mobile` tinyint(1) DEFAULT NULL,
  `is_robot` tinyint(1) DEFAULT NULL,
  `browser` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `mobile` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `robot` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `platform` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `referrer` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `domain` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `ip` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `continent_code` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `country_name` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `city` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `analytics_user_id` (`user_id`),
  KEY `analytics_product_id` (`product_id`),
  KEY `analytics_affil_user_id` (`affil_user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=64821325 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE `transactions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `transaction_id` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `user_id` int(11) NOT NULL,
  `pay_key` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `sender_email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `amount` decimal(10,2) DEFAULT NULL,
  `currency` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `status` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `analytics` int(11) DEFAULT NULL,
  `ip_address` varchar(46) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `session_id` varchar(60) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `eu_vat_applied` int(1) DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `tran_user_id` (`user_id`),
  KEY `transaction_id` (`transaction_id`(191)),
  KEY `tran_analytics` (`analytics`),
  KEY `tran_status` (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=10019356 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

上記をさらに最適化することはできません。 サマリーテーブルに関する実装アドバイスは素晴らしいものになります。 AWSではLAMPスタックを使用しています。 上記のクエリはRDS(m1.large)で実行されています。


あなたは以下を試みることができますアプローチ:

SELECT 
    analytics.source AS referrer, 
    COUNT(analytics.id) AS frequency, 
    SUM(sales) AS sales
FROM analytics
LEFT JOIN(
	SELECT transactions.Analytics, (CASE WHEN transactions.status = 'COMPLETED' THEN 1 ELSE 0 END) AS sales
	FROM analytics INNER JOIN transactions ON analytics.id = transactions.analytics
) Tra
ON analytics.id = Tra.analytics
WHERE analytics.user_id = 52094 
GROUP BY analytics.source 
ORDER BY frequency DESC 
LIMIT 10 


このクエリは、数百万のanalyticsレコードとtransactionsレコードを結合し、数百万のレコードの合計(ステータスチェックを含む)を計算します。 最初にLIMIT 10を適用してからジョインして合計を計算すると、クエリを高速化できます。 残念ながら、 GROUP BY適用した後に失われるjoinのanalytics.idが必要です。 しかし、おそらくanalytics.sourceは選択肢としてクエリを増やすことができます。

したがって私の考えは、サブクエリでanalytics.sourcefrequencyを返すように頻度を計算し、それによって制限し、この結果をメインクエリのanalyticsにフィルタリングしてから、残りの結合と計算をうまくいけば、記録の数を大幅に減らしました。

最小サブクエリ(注:結合なし、合計なし、10レコードを返します):

SELECT
    source,
    COUNT(id) AS frequency
FROM analytics
WHERE user_id = 52094
GROUP BY source
ORDER BY frequency DESC 
LIMIT 10

サブクエリxとして上記のクエリを使用した完全なクエリ:

SELECT
    x.source AS referrer,
    x.frequency,
    SUM(IF(t.status = 'COMPLETED', 1, 0)) AS sales
FROM
    (<subquery here>) x
    INNER JOIN analytics a
       ON x.source = a.source  -- This reduces the number of records
    LEFT JOIN transactions t
       ON a.id = t.analytics
WHERE a.user_id = 52094      -- We could have several users per source
GROUP BY x.source, x.frequency
ORDER BY x.frequency DESC

これにより予想されるパフォーマンスの向上が得られない場合は、予期しない順序で結合を適用することが原因である可能性があります。 ここで説明したように、「MySQLの実行順序を強制する方法はありますか? この場合は、 STRAIGHT_JOINで結合を置き換えることができます。


この質問は確かに多くの注目を集めていますので、すべての明白な解決策が試されていると確信しています。 私はクエリのLEFT JOINに対処する何かを見ませんでした。

私は、 LEFT JOIN文がクエリプランナをハッシュ結合に強制することに気付きましたが、これは少数の結果に対して高速ですが、多数の結果に対して非常に遅くなります。 @Rick Jamesの答えに書かれているように、元のクエリの結合はIDフィールドanalytics.idので、これにより多数の結果が生成されます。 ハッシュ結合は、ひどいパフォーマンス結果をもたらします。 以下の提案は、スキーマや処理の変更なしでこれを解決します。

集計はanalytics.sourceであるため、ソースごとに別々の集計を作成し、ソース別に集計を作成し、集計が完了するまで左結合を延期するクエリを試します。 これにより、索引を最もよく使用できるようにする必要があります(通常、これは大きなデータ・セットのマージ結合です)。

ここに私の提案があります:

SELECT t1.source AS referrer, t1.frequency, t2.sales
FROM (
  -- Frequency by source
  SELECT a.source, COUNT(a.id) AS frequency
  FROM analytics a
  WHERE a.user_id=52094
  GROUP BY a.source
) t1
LEFT JOIN (
  -- Sales by source
  SELECT a.source,
    SUM(IF(t.status = 'COMPLETED', 1, 0)) AS sales
  FROM analytics a
  JOIN transactions t
  WHERE a.id = t.analytics
    AND t.status = 'COMPLETED'
    AND a.user_id=52094
  GROUP by a.source
) t2
  ON t1.source = t2.source
ORDER BY frequency DESC 
LIMIT 10 

お役に立てれば。


サブクエリを試してみましょう:

SELECT a.source AS referrer, 
       COUNT(*) AS frequency,
       SUM((SELECT COUNT(*) FROM transactions t 
        WHERE a.id = t.analytics AND t.status = 'COMPLETED')) AS sales
FROM analytics a
WHERE a.user_id = 52094 
GROUP BY a.source
ORDER BY frequency DESC 
LIMIT 10; 

Plusは@Gordonの答え:analytics(user_id、id、source)とトランザクション(analytics、status)とまったく同じです。


パーティーに遅れる。 MySQLのキャッシュに1つのインデックスをロードする必要があると思います。 おそらくNLJは死のパフォーマンスです。 ここで私はそれを見る方法です:

パス

あなたの質問は簡単です。 2つのテーブルがあり、 "パス"は非常に明確です。

  • オプティマイザは、まずanalyticsテーブルを読み込む予定です。
  • オプティマイザは、 transactionsテーブルを2番目に読み込むことを計画する必要があります。 これはLEFT OUTER JOINを使用しているためです。 これについてはあまり議論しません。
  • また、 analyticsテーブルは6000万行で、最適なパスではできるだけ早くこの行をフィルタリングする必要があります。

アクセス

パスがクリアされたら、インデックスアクセスまたはテーブルアクセスを使用するかどうかを決定する必要があります。 どちらも長所と短所があります。 ただし、 SELECTパフォーマンスを向上させたいとします。

  • [インデックスアクセス]を選択する必要があります。
  • ハイブリッドアクセスは避けてください。 したがって、すべてのコストでテーブルアクセス(フェッチ)を回避する必要があります。 翻訳:参加しているすべての列をインデックスに配置します。

フィルタリング

繰り返しますが、 SELECT高性能を望みます。 したがって:

  • テーブルレベルではなく、インデックスレベルでフィルタリングを実行する必要があります。

行集計

フィルタリングの後、次のステップはGROUP BY analytics.sourceによって行を集約することです。 これは、 source列を索引の最初の列として配置することで改善できます。

パス、アクセス、フィルタリング、および集約に最適なインデックス

上記をすべて考慮して、すべての列をインデックスに含める必要があります。 次のインデックスは、応答時間を改善するはずです。

create index ix1_analytics on analytics (user_id, source, id);

create index ix2_transactions on transactions (analytics, status);

これらのインデックスは、上記の「パス」、「アクセス」、および「フィルタリング」戦略を実行します。

インデックスキャッシュ

最後に、これは重要です。セカンダリインデックスをMySQLのメモリキャッシュにロードします。 MySQLはNLJ(Nested Loop Join)を実行しています。これは、MySQLの用語集では「ref」であり、2番目のものにランダムに200k回アクセスする必要があります。

残念ながら、インデックスをMySQLのキャッシュにロードする方法についてはわかりません。 FORCEの使用は次のように動作します。

SELECT 
    analytics.source AS referrer, 
    COUNT(analytics.id) AS frequency, 
    SUM(IF(transactions.status = 'COMPLETED', 1, 0)) AS sales
FROM analytics
LEFT JOIN transactions FORCE index (ix2_transactions)
  ON analytics.id = transactions.analytics
WHERE analytics.user_id = 52094 
GROUP BY analytics.source 
ORDER BY frequency DESC 
LIMIT 10

十分なキャッシュスペースがあることを確認してください。 mysqlインデックスが完全にメモリに収まるかどうかを調べる方法

がんばろう! ああ、結果を投稿する。


最初のいくつかの分析...

SELECT  a.source AS referrer,
        COUNT(*) AS frequency,  -- See question below
        SUM(t.status = 'COMPLETED') AS sales
    FROM  analytics AS a
    LEFT JOIN  transactions AS t  ON a.id = t.analytics AS a
    WHERE  a.user_id = 52094
    GROUP BY  a.source
    ORDER BY  frequency DESC
    LIMIT  10 

aからtへのマッピングが「1対多」の場合、 COUNTSUM値が正しいか、値が膨大かどうかを検討する必要があります。 クエリが立つと、それらは「膨らんだ」。 JOINは集計の前に発生するので、トランザクションの数と完了した数を数えます。 私はそれが望ましいと仮定します。

注:通常のパターンはCOUNT(*)です。 COUNT(x) xNULLかどうかを調べることを意味しNULL 。 私はチェックが必要ではないと思う?

このインデックスはWHEREを処理し、「カバー」します。

 analytics:  INDEX(user_id, source, id)   -- user_id first

 transactions:  INDEX(analytics, status)  -- in this order

GROUP BYは、「ソート」を必要とする場合と、必要としない場合があります。 ORDER BYは、 GROUP BYとは異なり、間違いなく並べ替えが必要です。 グループ化された行全体をソートする必要があります。 LIMITのショートカットはありません。

通常、サマリテーブルは日付指向です。 つまり、 PRIMARY KEYには「日付」と他の次元が含まれています。 おそらく、dateとuser_idによるキー入力は意味をなさないでしょうか? 平均的なユーザーは1日に何回取引をしていますか? 少なくとも10の場合は、Summaryテーブルを検討してみましょう。 また、古いレコードをUPDATEingまたはDELETEingないことが重要です。 More

私はおそらく持っているだろう

user_id ...,
source ...,
dy DATE ...,
status ...,
freq      MEDIUMINT UNSIGNED NOT NULL,
status_ct MEDIUMINT UNSIGNED NOT NULL,
PRIMARY KEY(user_id, status, source, dy)

次に、クエリが

SELECT  source AS referrer,
        SUM(freq) AS frequency,
        SUM(status_ct) AS completed_sales
    FROM  Summary
    WHERE  user_id = 52094
      AND  status = 'COMPLETED'
    GROUP BY source
    ORDER BY  frequency DESC
    LIMIT  10 

速度は多くの要因から来ます

  • テーブルが小さくなる(表示する行が少なくなる)
  • JOINなし
  • より有用な指標

(それはまだ余分な並べ替えが必要です。)

要約表がなくても、いくつかのスピードアップがあるかもしれません...

  • テーブルはどれくらい大きいですか? `innodb_buffer_pool_sizeの大きさはどれくらいですか?
  • 嵩張り、繰り返しのある文字列の一部をNormalizingすると、そのテーブルはI / Oに束縛されません。
  • これはひどいです: KEY (transaction_id(191)) ; それを修正する5つの方法については、 hereを参照してください。
  • IPアドレスは255バイト、 utf8mb4_unicode_ciです。 (39)とasciiで十分です。

私は2つのテーブルからクエリを分離しようとします。 上位10のsourceだけが必要なので、まずそれらを取得してから、 transactionsからsales列を照会します。

SELECT  source as referrer
        ,frequency
        ,(select count(*) 
          from   transactions t  
          where  t.analytics in (select distinct id 
                                 from   analytics 
                                 where  user_id = 52094
                                        and source = by_frequency.source) 
                 and status = 'completed'
         ) as sales
from    (SELECT analytics.source
                ,count(*) as frequency
        from    analytics 
        where   analytics.user_id = 52094
        group by analytics.source
        order by frequency desc
        limit 10
        ) by_frequency

それはまた、 distinct


私は述語user_id = 52094がイラストレーション用であると仮定しています。アプリケーションでは、選択されたuser_idは変数です。

私はまた、ACIDプロパティはここではあまり重要ではないと仮定します。

(1)したがって、私は、ユーティリティテーブルを使用して、必要なフィールドだけを持つ2つのレプリカテーブルを管理しています(これは、前述のVladimirのインデックスと同様です)。

CREATE TABLE mv_anal (
  `id` int(11) NOT NULL,
  `user_id` int(11) DEFAULT NULL,
  `source` varchar(45),
  PRIMARY KEY (`id`)
);

CREATE TABLE mv_trans (
  `id` int(11) NOT NULL,
  `status` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `analytics` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE util (
  last_updated_anal int (11) NOT NULL,
  last_updated_trans int (11) NOT NULL
);

INSERT INTO util (0, 0);

ここで得られる利点は、元のテーブルの比較的小さな予測を読み込むことです。うまくいけば、OSレベルとDBレベルのキャッシュが機能し、より低速のセカンダリストレージから読み込まれるのではなく、より高速なRAMから読み込まれることです。 これは非常に大きな利益になる可能性があります。

以下は、2つのテーブルを更新した方法です(以下はcronで実行されるトランザクションです)。

-- TRANSACTION STARTS -- 

INSERT INTO mv_trans 
SELECT id, IF (status = 'COMPLETE', 1, 0) AS status, analysis 
FROM transactions JOIN util
ON util.last_updated_trans <= transactions.id

UPDATE util
SET last_updated_trans = sub.m
FROM (SELECT MAX (id) AS m FROM mv_trans) sub;

-- TRANSACTION COMMITS -- 

-- similar transaction for mv_anal.

(2)次に、順次スキャン時間を短縮するための選択性に取り組んでいきます。 私は、mv_anal上のuser_id、source、およびid(この順序で)にbツリーインデックスを構築する必要があります。

注:上記は、分析表に索引を作成するだけで実現できますが、そのような索引を作成するには、60M行の大きな表を読み取る必要があります。 私の方法では、非常に薄いテーブルだけを読むためにインデックスビルディングが必要です。 したがって、btreeをより頻繁に再構築することができます(テーブルが追加専用なのでスキューの問題に対処するため)。

これは、クエリの実行時に高い選択性が達成され、 btreeの問題が発生していないかどうかを確認する方法です。

(3)PostgreSQLでは、WITHサブクエリは常にマテリアライズされます。 MySQLの場合も同様です。 したがって、最適化の最後のマイルとして:

WITH sub_anal AS (
  SELECT user_id, source AS referrer, COUNT (id) AS frequency
  FROM mv_anal
  WHERE user_id = 52094
  GROUP BY user_id, source
  ORDER BY COUNT (id) DESC
  LIMIT 10
)
SELECT sa.referrer, sa.frequency, SUM (status) AS sales
FROM sub_anal AS sa 
JOIN mv_anal anal 
ON sa.referrer = anal.source AND sa.user_id = anal.user_id
JOIN mv_trans AS trans
ON anal.id = trans.analytics






sql-optimization