3

実行に時間がかかるこの特定のクエリがあり、同じテーブルに対する他のクエリは非常に高速に実行されます。Querycache は mysql で有効になっていますが、それでも以下のクエリは毎回 80 秒以上かかり、CPU の使用率は 100% を超えています。

クエリは Drupal によって生成されているため、変更できません。パフォーマンスを向上させるために他にできることはありますか?

クエリは次のとおりです。

select count(*) 
from (
    SELECT slk.key_id AS key_id 
    FROM slk slk  
        LEFT JOIN users users ON    slk.uid = users.uid 
        LEFT JOIN node node_users ON users.uid = node_users.uid 
            AND   node_users.type = 'profile'
) count_alias;

以下、プロフィール情報です。

+--------------------------------+-----------+
| Status                         | Duration  |
+--------------------------------+-----------+
| starting                       |  0.000029 | 
| checking query cache for query |  0.000093 | 
| Opening tables                 |  0.000210 | 
| System lock                    |  0.000007 | 
| Table lock                     |  0.000075 | 
| optimizing                     |  0.000008 | 
| statistics                     |  0.000113 | 
| preparing                      |  0.000027 | 
| executing                      |  0.000004 | 
| Sending data                   | 66.086903 | 
| init                           |  0.000027 | 
| optimizing                     |  0.000009 | 
| executing                      |  0.000018 | 
| end                            |  0.000003 | 
| query end                      |  0.000004 | 
| freeing items                  |  0.000049 | 
| storing result in query cache  |  0.000116 | 
| removing tmp table             |  0.033162 | 
| closing tables                 |  0.000106 | 
| logging slow query             |  0.000003 | 
| logging slow query             |  0.000085 | 
| cleaning up                    |  0.000007 | 
+--------------------------------+-----------+

クエリで説明すると、次のようになります。

| id | select_type | table      | type   | possible_keys         | key     | key_len | ref             | rows  | Extra                        |
|  1 | PRIMARY     | NULL       | NULL   | NULL                  | NULL    | NULL    | NULL            |  NULL | Select tables optimized away | 
|  2 | DERIVED     | slk        | ALL    | NULL                  | NULL    | NULL    | NULL            | 55862 |                              | 
|  2 | DERIVED     | users      | eq_ref | PRIMARY               | PRIMARY | 4       | gscom.slk.uid   |     1 | Using index                  | 
|  2 | DERIVED     | node_users | ref    | node_type,uid,idx_ctp | uid     | 4       | gscom.users.uid |     3 |                              | 

idx_ctpは ( uidtype) のインデックスです。

クエリ キャッシュは機能しており、以下は統計です。

show variables like '%query_cache%';:

| Variable_name                | Value    |
| have_query_cache             | YES      | 
| query_cache_limit            | 2097152  | 
| query_cache_min_res_unit     | 4096     | 
| query_cache_size             | 52428800 | 
| query_cache_type             | ON       | 
| query_cache_wlock_invalidate | OFF      |

mysql> show status like '%Qcache%';:

| Variable_name           | Value    |
| Qcache_free_blocks      | 1255     | 
| Qcache_free_memory      | 22902848 | 
| Qcache_hits             | 1484908  | 
| Qcache_inserts          | 1036344  | 
| Qcache_lowmem_prunes    | 95086    | 
| Qcache_not_cached       | 3975     | 
| Qcache_queries_in_cache | 14271    | 
| Qcache_total_blocks     | 30117    | 
4

2 に答える 2

2

これは貧弱なクエリです。テーブルからすべての55862行を選択し、slkすべての55862行を他の2つのテーブルに結合します。

MySQLはせいぜい、マスターテーブルの各行に対して詳細テーブルの対応する行に対してシークを実行する必要があるため、大きな結果セットのJOINはパフォーマンスを低下させます。行が多すぎる場合、MySQLは、非常に多くのシークを実行するよりも、詳細テーブル全体をスキャンする方が速いと判断します。

ypercubeが提案したように、に複数列のインデックスを作成するnode_users: (uid, type)と、(node_usersへの)2番目のテーブルの結合に役立ちます。

理想的には、このクエリがLEFT AND node_users.type = 'profile'OUTERJOINではなくINNERJOINを使用している場合、MySQLがクエリを逆方向にトラバースできるようにすることで、クエリを最適化できます。ただし、それらは結合のままであるため、MySQLは引き続きslkテーブル内のすべての行を取得する必要があり、そこから開始します。

このクエリを変更せずにパフォーマンスを向上させるためにできる唯一の追加のことは、カバーインデックスを使用してテーブルデータにヒットしないようにすることです。

これはより多くのメモリを使用しますが、ディスクにアクセスするのではなく、(メモリ内の)インデックスからすべての値を読み取ることができるため、より高速になることを願っています。これは、メモリ内のすべてのインデックスの保持をサポートするのに十分なRAMがあり、それを使用するようにMySQLを構成したことを意味します。

すでにカバーインデックスがありますusersUsing indexEXPLAINの結果を参照)。DERIVEDクエリの3行すべてをUsing indexExtra列に表示する必要があります。

次のカバーインデックスを追加で作成します。

slk: (key_id, uid)

これはすでに上で述べましたが、私はそれをここに再び含めているので、あなたはそれを忘れないでください:

node_users: (uid, type)

すべてのJOINを実行する必要があるため、ここでは画期的なパフォーマンスは得られませんが、ある程度の改善は得られます。どれだけ速いか教えてください。私は約2倍の速さだと思います。

于 2012-04-20T14:06:24.157 に答える
2

次のインデックスが必要です。

  • テーブルslk: (uid)
  • テーブルnode_users:(type, uid)

クエリは、サブクエリなしで次のように書き直すことができます。

SELECT COUNT(*) 
FROM slk 
    LEFT JOIN users 
        ON slk.uid = users.uid 
    LEFT JOIN node node_users 
        ON  users.uid = node_users.uid 
        AND node_users.type = 'profile'

そして、なぜあなたが を使うのか本当にわかりませんLEFT JOIN。おそらく使用INNER JOINして同じ結果を得ることができます。または、単純に次のように使用します。

SELECT COUNT(*) 
FROM slk 
于 2012-04-20T11:25:14.803 に答える