4

フィルタリングされた集計クエリを実行していますが、クエリの応答時間を短縮する方法について少しフィードバックをお願いします。

クエリ (実行されますが、平均 400 秒以上かかります):

select data_date,sum(closeprice) from moving_avgs
where
    symbol in (select distinct symbol from moving_avgs
                where
                ma200_close     >= 5.00 and
                ma200_volume    >= 400000 and
                data_date   = (select min(data_date) from moving_avgs
                                where year(data_date) = 2007) 
                )
group by data_date;

私の EXPLAIN クエリの読み取り (この環境で読み取るようにフォーマットされています):

id:         1
select_type:    PRIMARY
table:      moving_avgs
type:       ALL
possible_keys:  NULL
key:        NULL
key_len:        NULL
ref:        NULL
rows:       6250033
Extra:      Using where; Using temporary; Using filesort

id:         2
select_type:    DEPENDENT SUBQUERY
table:      moving_avgs
type:       unique_subquery
possible_keys:  PRIMARY,symbol,data_date,ma200_close,ma200_volume
key:        PRIMARY
key_len:        29
ref:        func,const
rows:       1
Extra:      Using where

id:         3
select_type:    SUBQUERY
table:      moving_avgs
type:       index
possible_keys:  NULL
key:        data_date
key_len:        3
ref:        NULL
rows:       6250033
Extra:      Using where; Using index

私の my.ini [mysqld] および [myisamchk] セクションを読み取ります (4GB デュアル プロセッサ AMD ラップトップで実行):

[mysqld]
port        = 3306
socket      = /tmp/mysql.sock
skip-external-locking
key_buffer_size = 512M
max_allowed_packet = 20M
table_open_cache = 256
sort_buffer_size = 8M
read_buffer_size = 8M
read_rnd_buffer_size = 16M
myisam_sort_buffer_size = 256M
thread_cache_size = 8
query_cache_size= 132M
basedir=c:/wamp/bin/mysql/mysql5.5.24
log-error=c:/wamp/logs/mysql.log
datadir=c:/wamp/bin/mysql/mysql5.5.24/data
# Try number of CPU's*2 for thread_concurrency
thread_concurrency = 8

[myisamchk]
key_buffer_size = 256M
sort_buffer_size = 256M
read_buffer = 4M
write_buffer = 4M

ありがとう!

4

4 に答える 4

4

SHOW CREATE TABLE の結果を挙げていただけますか?

また、このバリアントを試して、所要時間を確認してください:

SELECT  
    data_date,  
    sum(closeprice)  
FROM moving_avgs  
INNER JOIN  
(  
    SELECT distinct symbol  
    FROM moving_avgs  
    WHERE    
        ma200_close     >= 5.00 and    
        ma200_volume    >= 400000 and  
        data_date   =  
        (  
            SELECT min(data_date)  
            FROM moving_avgs  
            WHERE year(data_date) = 2007  
        )   
) symbols ON symbols.symbol = moving_avgs.symbol  
GROUP BY data_date;  

速度低下の 3 つの原因を (組み合わせて、または個別に) 疑っています。最初の 2 つの理由は非常に単純です。

(1) テーブルのインデックスが適切に設計されていない可能性があります。EXPLAIN 情報で適切なインデックスの使用が見られません。

(2) WHERE でのサブクエリの設計方法により、エンジンが「シンボル」にあるインデックスを使用しないように強制される可能性があります。そうしないと、インデックスが提供するパフォーマンスが失われます。EXPLAIN 出力は、この損失のように見えます。

(3) インデックスのロールについて話さずに (2) を述べる別の方法は、外部クエリとの関係を誤って推測することに基づいて、エンジンがメインのサブクエリ (WHERE 内のサブクエリ) で非効率的に動作している可能性があるということです (つまり、は関係があると考えています (クエリが相関サブクエリであり、その関係について間違った選択をしている)。

[注: WHERE の記述方法では、サブクエリは相関クエリではなく、効率的に実行でき、IN は比較的効率的に解決できます (ただし、インデックスの利点がない可能性があります)。ただし、エンジンがこの状況を適切に解釈していない可能性があります。ネストされたサブクエリの状況がやや複雑で、エンジンが誤解する可能性があります]。

いずれにせよ、サブクエリを結合に移動すると、エンジンがサブクエリをクエリの残りの部分に非効率的に関連付けようとする可能性がなくなるため、このようなシナリオを修正できます。サブクエリが結合のソースである場合、クエリの残りの本文を考慮する前に、エンジンはサブクエリを解決する必要があります。これにより、サブクエリと、エンジンが作成している可能性のある残りのクエリとの関係に関する不適切な推論が排除されます。

于 2012-12-22T04:13:52.557 に答える
2

この条件は次のように思われます。

(select min(data_date) from moving_avgs
                            where year(data_date) = 2007)

すべての行の年を計算するため、費用がかかります。また、存在する可能性のあるインデックスを使用することはできdata_dateません (テーブルとインデックスの定義をまだ示していないため、わかりません)。 )。

にインデックスがある場合はdata_date、それを次のように変更することで、MySQL にインデックスを使用させることができます。

(select min(data_date) from moving_avgs
where data_date between '01-01-2007' and '12-31-2007')

これは、MySQL が日付を指定する方法ではないかもしれないことに注意してください。開始点と終了点を指定して、インデックスを使用できるようにします。すべての行で年を計算するように要求している場合、それは不可能です。

于 2012-12-22T05:27:45.980 に答える
1

1) 2 つの my.ini 変数を作成して設定する:

max_heap_table_size = 256M

tmp_table_size = 512M

そして、2) 3 番目の変数を増やします。

myisam_sort_buffer_size = 256M

3) 3 つの単一フィールド インデックスを削除し、4 フィールド インデックスに置き換える(INDEX: data_date-ma200_close-ma200_volume-symbol)

178秒までタイムを縮めることができました。

4) に加えて、@DWright のおかげで、クエリを再構築することで、67 秒に短縮されました。

于 2012-12-22T05:17:53.780 に答える
0

私が見る 1 つの方法は、毎年の min(data_date) を事前に計算することです。そうすれば、外側のクエリのすべてのレコードに対して SELECT クエリを実行する必要がなくなります。ただし、このテーブルを維持して、任意の時点で特定の年の最小 data_date が常に保持されるようにする必要があります。

于 2012-12-22T03:11:00.053 に答える