3

私は codeigniter と mysql を使用しており、200 MB のメモリと 1 GB の CPU を備えたサーバーに適用され、テーブル a (インデックス: idx_cat) に 40.000 行、カテゴリに 44 行 (インデックス: プライマリ) があり、上位 4 つを取得する必要があります。各カテゴリで、ここに私のクエリがあります

SELECT id,title,preview,created,image,dummy,name 
FROM
 (
 select news.id AS id,news.title AS title,preview,created,news.image,category_id ,
         @num := if(@cat = category_id, @num + 1, 1) as row_number,
         @cat := category_id as dummy,
        name,d_order
 from news use index (idx_cat) inner join category b on category_id=b.id
 where 
    news.category_id in (9,8,3,35,57,56,15,58,41,42,43,44,34,52,37,38,36,11) and
    news.status = 1 
 having row_number <= 4 
 order by dummy ASC,news.created desc
 ) as a 
order by d_order ASC,created DESC



id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   PRIMARY     <derived2>  ALL     NULL    NULL    NULL    NULL    **29639**   Using filesort
2   DERIVED     b   ALL     PRIMARY,id  NULL    NULL    NULL    **44**  Using where; Using temporary; Using filesort
2   DERIVED     news    ref     idx_cat     idx_cat     **4**   b.id    846     Using where    

そして、他の6つの単純な結合を取得しました

   select id,name from others a inner join b on a.cat_id = b.id

サイトの読み込みは約 1 秒または 2 秒と非常に高速ですが、読み込み中に別のタブを開くと、5 ~ 7 秒ほど遅くなります。

奇妙なことに、CPU 使用率は 100% に達し、メモリ使用率は 1 つのビューを終了するために +_ 40 MB になりましたが (他に開いているものがないことを確認してください)、CI プロファイリングはユーザー 4MB とだけ言っています。

また、ロード モデル、ヘルパー、ライブラリをオンデマンドで 2 つ (URL とフォーム) だけにして、オートロード ファイルに入れました。

そして、5 から 10 までのウィンドウを開くと、メモリ不足と表示されます。

4

1 に答える 1

2

内側の選択の結果のサイズを縮小するには、フィールドの選択と結合を外側の選択に移動named_orderます

SELECT id,title,preview,created,image,dummy,name,d_order FROM
     (
 select news.id AS id,news.title AS title,preview,created,news.image,category_id ,
         @num := if(@cat = category_id, @num + 1, 1) as row_number,
         @cat := category_id as dummy
 from news use index (idx_cat) 
 where 
    news.category_id in (9,8,3,35,57,56,15,58,41,42,43,44,34,52,37,38,36,11) and
    news.status = 1 
 having row_number <= 4 
 order by dummy ASC,news.created desc
 ) as a inner join category b on category_id=b.id
order by d_order ASC,created DESC

おそらく行数はまだ大きいですが、メモリを減らしました。選択している方法では、非常にコストのかかる計算で、ニュース テーブル全体を処理してから、不要な行を削除する必要があります。news.id、cat.id、および最小フィールドだけでニュースの事前選択を行うと、より効率的になる可能性があるため、ニュース本体の重いフィールドは重い選択の外にあります。

SELECT id,c.title,c.preview,created,c.image,dummy,name,d_order FROM
     (
 select news.id AS id,category_id ,
         @num := if(@cat = category_id, @num + 1, 1) as row_number,
         @cat := category_id as dummy
 from news use index (idx_cat) 
 where 
    news.category_id in (9,8,3,35,57,56,15,58,41,42,43,44,34,52,37,38,36,11) and
    news.status = 1 
 having row_number <= 4 
 order by dummy ASC,news.created desc
 ) as a 
    inner join category b on category_id=b.id
    inner join news c on a.id = c.id
    order by d_order ASC,created DESC

おそらくいくつかの構文エラーがありますが、ここに書くのは少し難しく、テストするデータがありません。私が問題を理解していることを願っています。

于 2012-11-19T12:56:03.093 に答える