2016-10-11 5 views
0

私のサイトが長すぎて内容を読み込めず、mysqlサービスが使用するCPU負荷が200%になることがあります。表を調べると、すべての列が索引として使用されていることがわかりました。これは正しいです?パフォーマンスに影響する可能性がありますか?mysqlデータベースのすべての列をインデックスするのは正しいですか?

私のサーバー構成:16GB RAM、3.4GHz ほとんどのテーブルには約25k〜50k行があります。そして10〜20列。すべての列のインデックス作成

All tables indexing are like this example. All columns as indexes

+0

実際には大きなデータベースとは見なされませんが、私はそれを小さなものと呼んでいます。 – RiggsFolly

+0

不必要なインデックスはリソースの無駄です。しかし、どの索引が最も適切かを判断することは、実行されている実際の照会と、それらの照会のパフォーマンスの期待値に依存します。パフォーマンスチューニングは「インデックス」よりもはるかに多いです。その表のすべての索引が適切である可能性があります。提供された情報から、私たちは「この特定のインデックスセットが最も適切であることを明らかにした*慎重な分析」と「*私はちょうど私が正しいインデックスを持っていないことで燃えた* " – spencer7593

+0

あなたのためにそれを整理するために誰か(私ではない)50ドルを与える – Drew

答えて

0

が正しくありません。これは、書き込み操作のパフォーマンスに影響します。追加の索引を追加するたびに、書き込み操作後に更新する時間が必要になります。また、各索引は追加スペースを必要とします。検索に使用する列のみにインデックスを付ける必要があります。

+0

...索引付けの候補は、外部キー、結合述部、ORDER BY、GROUP BYなどで使用される列です(一部は「検索専用」のカテゴリーには含まれません)。 – spencer7593

2

いいえ、すべての列をインデックスしません。 WHERE句に特に関与する列をインデックス化します。また、それらがORDER BYに含まれる場合もあります。

SELECT name FROM users WHERE type='admin' AND active=1 

あなたは、インデックスをお勧めします。この場合:

SELECT name FROM users WHERE type='admin' 

この場合、あなたはactive,typeにインデックスをしたいと思います:あなたはtypeにインデックスがしたいと思います。この場合、

on active,type,name

SELECT name FROM users WHERE type-='admin' AND active=1 ORDER BY name LIMIT 10 

more indexes遅い書き込みは追加されますが、速い読み取りが行われます。これは古典的なトレードオフです。あなたが必要とするインデックスを慎重に評価し、具体的なメリットがある場合にのみ適用してください。彼らがそこにいなければならないと感じるので、それらを叩くだけではいけません。

超小型テーブルでは、< 1000行のインデックスを持つテーブルは、テーブルスキャンにそれほど時間がかからないため、あまり役に立ちません。些細なことでも、彼らは絶対不可欠です。

パフォーマンスの問題が発生した場合は、スキーマがインデックスの欠如ではなく、最大の障害であることをお勧めします。

+2

.. 。+外部キー、および結合述部の列、および場合によってはGROUP BYは、索引(EXPLAIN出力の "Using group by group by")を使用して満たすことができます。また、一部のクエリでは、「カバーインデックス」が他のインデックスよりも有益です。 +10。また、忙しいシステムで考慮すべき重要なのは、ロックの競合です。 (ストレージエンジンの選択はパフォーマンスに影響を与える可能性があります) – spencer7593

+1

@ spencer7593すべての有効な懸念事項がありますが、最も基本的な例です。インデックスを追加する理由の網羅的なリストは、あなたが指摘しているようにかなり長いです。 – tadman

+1

私は同意します。非常にまれで例外的な状況においてのみ、最も適切なインデックスのセットは、テーブル内の各カラムのシングルトンインデックスになります。 OPテーブルのそのインデックスのセットは、膝の反動の結果であるように見えます。「*私はインデックスがないときに燃えたので、すべての列にインデックスを追加します*」。 (それは部分的に理解できますが、適切なインデックスの作成が、パフォーマンス上の問題に対する夜間の「奇跡の治癒」のように見える場合...すべてのパフォーマンスの問題に対する解毒剤とみなされます) – spencer7593

0

いいえ、すべての列にインデックスを付けるべきではありません。データを書き込むと処理が遅くなります。 CPUが時々200%に達するのは普通ではありません。私はあなたのSQLをチェックすることをお勧めします。

SELECT文を最適化すると便利です。

http://dev.mysql.com/doc/refman/5.6/en/statement-optimization.html

1.Optimizeキャッシュを使用してクエリ。関数の代わりにパラメータを使用してみてください。

(@のtadmanの提案のおかげで)あなたは賢明に選択

// no cache 
$sql = "SELECT username FROM user WHERE signup_date >= CURDATE()"; 

// cache 
$today = date("Y-m-d"); 
$sql = "SELECT username FROM user WHERE signup_date >= '$today'"); 

2.EXPLAIN。潜在的なパフォーマンスの問題を見つけるのに役立ちます。

EXPLAIN select name,phone from user where name="JakLiao"; 

3.最初の1行の結果のみが必要な場合は、「LIMIT N」を使用します。

SELECT * FROM user WHERE country = 'China' limit 1; 

4. where句で必要なときにインデックスを使用します。

//row "name" should add index. 
select * from user where name LIKE 'Jak%' limit 10; 

5.テーブルを結合するときにインデックスを使用します。

select company_name FROM users LEFT JOIN companies ON (users.state = companies.state) WHERE users.id = 123; 

6.避けてください "*を選択し、"

//not suggest 
SELECT * FROM user WHERE user_id = 1; 
//suggest 
SELECT username FROM user WHERE user_id = 1; 

7. PROCEDURE(ANALYZE)、MYSQLは、分析データベースとデータをお手伝いします。 8.テーブルの行を知りたいときはCOUNT(1)を指定します。

//not suggest 
SELECT count(*) FROM user; 
//suggest 
SELECT count(1) FROM user; 
+0

ヒントありがとうございました。非常に役立ちました。MySQLの変数はどうですか?最大接続、タイムアウト...時々私は "接続が多すぎます"というエラーが表示される –

+0

ここにいくつかの良い提案があります。私は8番を置き換えるかもしれません。私は 'SQL_CALC_FOUND_ROWS'を避けることを推奨しません。 「COUNT(*)」と「COUNT(1)」の間にあると言われる差異は神話です。数字1の場合、MySQLクエリキャッシュは危険な獣です。 'NOW()'以外にもクエリをキャッシュすることができない多くの理由があります。 (私たちの店では、 'query_cache_type = 2'を持っていて、キャッシュしたいステートメントに' SQL_CACHE'ヒントを入れています)。 – spencer7593

+1

ここでのアドバイスはほとんど妥当ですが、古いmysql_query関数を使うとこの答えはかなり混乱します。この関数は死んでおり、PHP 7から削除されています。可能な限り、使用されているインタフェースとは独立した助言を与えてください。そのPDOかmysqliか何らかのORMでなければなりません。 – tadman

関連する問題