アプリケーション開発者が犯す一般的なデータベース開発の間違いは何ですか?
アプリケーション開発者が犯す一般的なデータベース開発の間違いは何ですか?
回答:
1.適切なインデックスを使用しない
これは比較的簡単な方法ですが、それでも常に発生します。外部キーにはインデックスが必要です。でフィールドを使用しているWHERE
場合は、(おそらく)インデックスが必要です。このようなインデックスは、多くの場合、実行する必要のあるクエリに基づいて複数の列をカバーする必要があります。
2.参照整合性を強制しない
データベースはここで異なる場合がありますが、データベースが参照整合性をサポートしている場合(つまり、すべての外部キーが存在するエンティティを指すことが保証されている場合)、それを使用する必要があります。
MySQLデータベースでこの障害が発生するのはよくあることです。MyISAMでサポートされているとは思いません。InnoDBはそうします。MyISAMを使用している人や、InnoDBを使用しているがとにかくそれを使用していない人を見つけるでしょう。
詳細はこちら:
3.代理(技術)主キーではなく自然な主キーを使用する
自然キーは、(表向きに)一意である、外部的に意味のあるデータに基づくキーです。一般的な例は、製品コード、2文字の州コード(US)、社会保障番号などです。代理または技術主キーは、システムの外部ではまったく意味がないものです。これらは純粋にエンティティを識別するために発明され、通常は自動インクリメントフィールド(SQL Server、MySQL、その他)またはシーケンス(特にOracle)です。
私の意見では、常に代理キーを使用する必要があります。この問題はこれらの質問で出てきました:
これは、議論の余地のあるトピックであり、普遍的な合意は得られません。自然キーで問題がないと考える人もいますが、間違いなく不必要である以外に、代理キーに対する批判はありません。あなたが私に尋ねるなら、それはかなり小さな欠点です。
国も存在しなくなる可能性があることを覚えておいてください(たとえば、ユーゴスラビア)。
4.動作する必要DISTINCT
があるクエリを書く
これはORMで生成されたクエリでよく見られます。Hibernateからのログ出力を見ると、すべてのクエリが次で始まることがわかります。
SELECT DISTINCT ...
これは、重複した行を返さないようにして、重複したオブジェクトを取得しないようにするためのちょっとしたショートカットです。あなたは時々、これをしている人々も見るでしょう。あなたがそれをあまりにも多く見るならば、それは本当の赤い旗です。それDISTINCT
は悪くないか、有効なアプリケーションを持っていません。それは(両方の点で)行いますが、正しいクエリを作成するための代理または一時的なギャップではありません。
私の意見では事態が悪化し始めているのは、開発者が実質的なクエリを作成し、テーブルを結合しているときに、突然、彼は重複(またはそれ以上)の行と即時の応答を取得しているように見えることに気づきました...この「問題」に対する彼の「解決策」は、DISTINCTキーワードを使用 して、彼のすべての問題を解決することです。
5.結合よりも集約を優先する
データベースアプリケーション開発者によるもう1つの一般的な間違いはGROUP BY
、結合と比較してはるかに高価な集計(つまり、句)を比較できないことです。
これがどれだけ広まっているかを理解するために、ここでこのトピックについて何度か書いてきましたが、多くの反対意見が出されました。例えば:
SQLステートメントから-「結合」対「グループ化および所有」:
最初のクエリ:
SELECT userid FROM userrole WHERE roleid IN (1, 2, 3) GROUP by userid HAVING COUNT(1) = 3
クエリ時間:0.312秒
2番目のクエリ:
SELECT t1.userid FROM userrole t1 JOIN userrole t2 ON t1.userid = t2.userid AND t2.roleid = 2 JOIN userrole t3 ON t2.userid = t3.userid AND t3.roleid = 3 AND t1.roleid = 1
クエリ時間:0.016秒
そのとおり。私が提案した結合バージョンは、集約バージョンよりも20倍高速です。
6.ビューを通じて複雑なクエリを単純化しない
すべてのデータベースベンダーがビューをサポートしているわけではありませんが、ビューをサポートしている場合は、慎重に使用すればクエリを大幅に簡略化できます。たとえば、あるプロジェクトでは、CRMの一般的なPartyモデルを使用しました。これは非常に強力で柔軟なモデリング手法ですが、多くの結合につながる可能性があります。このモデルには次のものがありました。
例:
したがって、テッドを雇用主にリンクするために5つのテーブルが結合されています。すべての従業員は個人(組織ではない)であると想定し、次のヘルパービューを提供します。
CREATE VIEW vw_employee AS
SELECT p.title, p.given_names, p.surname, p.date_of_birth, p2.party_name employer_name
FROM person p
JOIN party py ON py.id = p.id
JOIN party_role child ON p.id = child.party_id
JOIN party_role_relationship prr ON child.id = prr.child_id AND prr.type = 'EMPLOYMENT'
JOIN party_role parent ON parent.id = prr.parent_id = parent.id
JOIN party p2 ON parent.party_id = p2.id
そして、突然、必要なデータの非常に単純なビューが得られますが、非常に柔軟なデータモデルに基づいています。
7.入力を無害化しない
これは巨大なものです。今はPHPが好きですが、何をしているのかわからない場合は、攻撃に対して脆弱なサイトを作成するのは非常に簡単です。小さなボビーテーブルの話ほど、それをうまくまとめたものはありません。
URL、フォームデータ、Cookieを使用してユーザーが提供するデータは、常に敵対的で無害化されたものとして扱う必要があります。期待どおりの結果が得られていることを確認してください。
8.準備済みステートメントを使用しない
準備済みステートメントとは、クエリをコンパイルして、挿入、更新、およびWHERE
句で使用されるデータを差し引いて、後で提供する場合です。例えば:
SELECT * FROM users WHERE username = 'bob'
対
SELECT * FROM users WHERE username = ?
または
SELECT * FROM users WHERE username = :username
プラットフォームによって異なります。
これを実行することでデータベースがひどい目に遭うのを見てきました。基本的に、最新のデータベースが新しいクエリに遭遇するたびに、それをコンパイルする必要があります。以前に見たクエリに遭遇した場合は、データベースに、コンパイルされたクエリと実行プランをキャッシュする機会を与えています。多くのクエリを実行することで、データベースにそれを把握し、それに応じて最適化する機会をデータベースに与えます(たとえば、コンパイルされたクエリをメモリに固定することによって)。
準備されたステートメントを使用すると、特定のクエリが使用される頻度に関する意味のある統計も得られます。
準備済みステートメントは、SQLインジェクション攻撃からの保護も強化されます。
9.十分に正規化していない
データベースの正規化は、基本的にはデータベース設計を最適化するプロセス、またはデータをテーブルに編成する方法です。
ちょうど今週、私は誰かが配列を爆破してデータベースの単一のフィールドに挿入したコードに遭遇しました。それを正規化すると、その配列の要素は子テーブルの個別の行として扱われます(つまり、1対多の関係)。
これは、ユーザーIDのリストを保存するための最良の方法でも発生しました。
他のシステムでは、リストがシリアライズされたPHP配列に格納されているのを見てきました。
しかし、正規化の欠如にはさまざまな形があります。
もっと:
10.正規化しすぎ
これは前の点と矛盾しているように見えるかもしれませんが、正規化は多くの場合と同様にツールです。それは目的そのものであり、目的ではありません。多くの開発者はこれを忘れて、「手段」を「終わり」として扱い始めると思います。ユニットテストは、この典型的な例です。
私はかつて、次のようなクライアントのための巨大な階層を持つシステムに取り組みました。
Licensee -> Dealer Group -> Company -> Practice -> ...
つまり、意味のあるデータを取得する前に、約11のテーブルを結合する必要がありました。これは、あまりにも多く行われた正規化の良い例でした。
要点は、注意深く検討された非正規化はパフォーマンスに大きなメリットをもたらす可能性がありますが、これを行う場合は十分に注意する必要があります。
もっと:
11.排他的なアークの使用
排他的弧は、テーブルが2つ以上の外部キーで作成され、そのうちの1つだけが非nullになる可能性がある一般的な間違いです。 大ミス。 1つには、データの整合性を維持することがはるかに困難になります。結局のところ、参照整合性があっても、これらの外部キーの2つ以上の設定を妨げるものはありません(複雑なチェック制約にもかかわらず)。
以下からのリレーショナルデータベース設計の実用ガイド:
コードを書くのが面倒で、メンテナンスがより困難になるという正当な理由から、可能な限り排他的なアークの構築はしないよう強くお勧めします。
12.クエリのパフォーマンス分析をまったく行わない
プラグマティズムは、特にデータベースの世界で最高権力を握っています。原則に固執して、それがドグマになった場合は、おそらく間違いを犯しているでしょう。上記の集計クエリの例を見てみましょう。集約バージョンは「見栄えがいい」ように見えるかもしれませんが、そのパフォーマンスは悲惨です。パフォーマンスの比較は議論を終わらせるべきでした(しかし、それはしませんでした)より多くの点で:最初にそのような悪質な情報のあるビューを噴出することは無知であり、危険ですらあります。
13. UNION ALL、特にUNIONコンストラクトへの過度の依存
SQL用語のUNIONは、合同なデータセットを連結するだけです。つまり、同じタイプと同じ数の列を持っています。それらの違いは、UNION ALLは単純な連結であり、可能な限り優先される必要があるのに対し、UNIONは重複したタプルを削除するために暗黙的にDISTINCTを実行することです。
UNITINはDISTINCTのようにその場所を持っています。有効なアプリケーションがあります。しかし、特にサブクエリでそれらの多くを実行している場合は、おそらく何かが間違っています。これは、クエリの構成が不十分であるか、データモデルが適切に設計されておらず、そのようなことを強いられている場合です。
UNIONは、特に結合または従属サブクエリで使用される場合、データベースを不自由にする可能性があります。可能な限りそれらを避けるようにしてください。
14.クエリでのOR条件の使用
これは無害に見えるかもしれません。結局、ANDはOKです。または大丈夫でしょうか?違う。基本的にAND条件を制限し、一方、データセットをOR条件は、成長ではなく、最適化に役立つ方法でそれを。特に、さまざまなOR条件が交差する可能性があるため、オプティマイザが結果のDISTINCT操作を効果的に実行する必要がある場合。
悪い:
... WHERE a = 2 OR a = 5 OR a = 11
より良い:
... WHERE a IN (2, 5, 11)
これで、SQLオプティマイザが最初のクエリを2番目のクエリに効果的に変換できます。しかし、そうではないかもしれません。しないでください。
15.高性能ソリューションに適したデータモデルを設計していない
これは、定量化するのが難しいポイントです。それは通常、その効果によって観察されます。比較的単純なタスクに対して危険なクエリを作成している場合や、比較的単純な情報を見つけるためのクエリが効率的でない場合は、おそらくデータモデルが不十分です。
いくつかの点で、このポイントは以前のすべてを要約していますが、クエリの最適化などの処理は、2番目に実行する必要があるときに最初に実行されることが多いという、より注意深い話です。何よりもまず、パフォーマンスを最適化する前に、適切なデータモデルがあることを確認する必要があります。クヌースが言ったように:
時期尚早の最適化はすべての悪の根源です
16.データベーストランザクションの不適切な使用
特定のプロセスのすべてのデータ変更はアトミックである必要があります。つまり、操作が成功すると、完全に成功します。失敗した場合、データは変更されません。-「半完成」の変更の可能性があってはなりません。
理想的には、これを実現する最も簡単な方法は、システム全体の設計が、単一のINSERT / UPDATE / DELETEステートメントを通じてすべてのデータ変更をサポートするように努力することです。この場合、データベースエンジンが自動的に行う必要があるため、特別なトランザクション処理は必要ありません。
ただし、データを一貫した状態に保つためにプロセスが1つの単位として複数のステートメントを実行する必要がある場合は、適切なトランザクション制御が必要です。
この点に関して、データベース接続層とデータベースエンジンがどのように相互作用するかについて、細心の注意を払うこともお勧めします。
17.「セットベース」のパラダイムを理解していない
SQL言語は、特定の種類の問題に適した特定のパラダイムに従います。ベンダー固有のさまざまな拡張機能にもかかわらず、言語は、Java、C#、Delphiなどの言語では些細な問題に対処するのに苦労しています。
この理解の欠如は、いくつかの方法で現れます。
責任の明確な分担を決定し、適切なツールを使用して各問題を解決するよう努めます。
開発者による主要なデータベース設計とプログラミングの誤り
利己的なデータベースの設計と使用法。 多くの場合、開発者はデータベースをデータ内の他の利害関係者のニーズを考慮せずに個人の永続オブジェクトストアとして扱います。これは、アプリケーションアーキテクトにも適用されます。データベースの設計とデータの整合性が低いと、サードパーティがデータを操作することが難しくなり、システムのライフサイクルコストが大幅に増加する可能性があります。レポートとMISは、アプリケーション設計のいとこではない傾向があり、後付けとしてのみ行われます。
非正規化データの悪用。非正規化データをやりすぎて、アプリケーション内でそれを維持しようとすることは、データの整合性の問題のレシピです。非正規化は慎重に使用してください。クエリに結合を追加したくないことは、非正規化の言い訳にはなりません。
SQLを書くのが怖い。 SQLはロケット科学ではなく、実際にはその仕事をするのが非常に得意です。O / Rマッピングレイヤーは、単純でそのモデルによく適合する95%のクエリを実行するのに非常に適しています。場合によっては、SQLが最適な方法です。
独断的な「ストアドプロシージャなし」ポリシー。 ストアドプロシージャが悪であると信じるかどうかに関係なく、このような独断的な態度はソフトウェアプロジェクトには当てはまりません。
データベース設計を理解していない。 正規化はあなたの友人であり、ロケット科学ではありません。 結合とカーディナリティーはかなり単純な概念です。データベースアプリケーションの開発に携わっている場合、それらを理解しない言い訳はありません。
ストアドプロシージャへの過度の使用や依存。
一部のアプリケーション開発者は、ストアドプロシージャを中間層/フロントエンドコードの直接の拡張と見なしています。これは、Microsoftスタック開発者(私はその1つですが、私はそれから成長しました)に共通の特性であると思われ、複雑なビジネスロジックとワークフロー処理を実行する多くのストアドプロシージャを生成します。これは他の場所で行う方がはるかに優れています。
ストアドプロシージャは、実際の技術的要因がその使用を必要とすることが実際に証明されている場合(たとえば、パフォーマンスやセキュリティ)に役立ちます。
私は最近、ビジネスロジックとルールの70%が1400 SQL Serverストアドプロシージャ(UIイベントハンドラーの残りの部分)に実装された大規模なDelphiデスクトップアプリケーションの維持と強化を支援する必要がありました。これは、主にTSQLへの効果的なユニットテストの導入の難しさ、カプセル化の欠如、不十分なツール(デバッガー、エディター)による悪夢でした。
過去にJavaチームと協力して、私はすぐに、その環境ではまったく正反対のことが成り立つことがすぐにわかりました。Javaアーキテクトがかつて私に言った:「データベースはデータ用であり、コードではありません。」
最近では、ストアドプロシージャをまったく考慮しないのは間違いだと思いますが、有用な利点を提供する状況では(デフォルトではなく)慎重に使用する必要があります(他の回答を参照)。
一番の問題?彼らはおもちゃのデータベースでのみテストします。したがって、データベースが大きくなったときにSQLがクロールすることを彼らは理解しておらず、誰かが一緒に来て修正する必要があります(聞こえる音は私の歯を磨く音です)。
インデックスを使用しません。
相関サブクエリが原因のパフォーマンスの低下
ほとんどの場合、相関サブクエリは避けたいものです。サブクエリ内に、外部クエリからの列への参照がある場合、サブクエリは相関しています。これが発生した場合、サブクエリは返された行ごとに少なくとも1回実行され、相関サブクエリを含む条件が適用された後に他の条件が適用されると、さらに実行される可能性があります。
不自然な例とOracleの構文は許してください。しかし、ある店舗で1日の売上が$ 10,000未満になったときから、いずれかの店舗で雇用されたすべての従業員を検索したいとします。
select e.first_name, e.last_name
from employee e
where e.start_date >
(select max(ds.transaction_date)
from daily_sales ds
where ds.store_id = e.store_id and
ds.total < 10000)
この例のサブクエリは、store_idによって外部クエリに関連付けられ、システム内のすべての従業員に対して実行されます。このクエリを最適化できる1つの方法は、サブクエリをインラインビューに移動することです。
select e.first_name, e.last_name
from employee e,
(select ds.store_id,
max(s.transaction_date) transaction_date
from daily_sales ds
where ds.total < 10000
group by s.store_id) dsx
where e.store_id = dsx.store_id and
e.start_date > dsx.transaction_date
この例では、from句のクエリはインラインビュー(これもOracle固有の構文)であり、一度だけ実行されます。データモデルによっては、このクエリはおそらくはるかに速く実行されます。従業員数が増えるにつれて、最初のクエリよりもパフォーマンスが向上します。最初のクエリは、従業員が少なく店舗数が多く(おそらく、店舗の多くに従業員がいない場合)、daily_salesテーブルにstore_idのインデックスが作成されている場合、実際にはパフォーマンスが向上します。これはありそうなシナリオではありませんが、相関クエリが代替クエリよりもパフォーマンスが優れている可能性があることを示しています。
ジュニア開発者がサブクエリを何度も関連付けているのを見てきましたが、通常、パフォーマンスに深刻な影響を与えています。ただし、相関サブクエリを削除する場合は、パフォーマンスの低下を防ぐために、前後の説明計画を必ず確認してください。
「実際の」データベースの代わりにAccessを使用する。SQL Express、MySQL、SQLiteのような、小さくて無料のデータベースがたくさんあります。多くの場合、アプリは予期しない方法でスケーリングする必要があります。
追加したいのは、パフォーマンスの高いコードよりも「エレガントな」コードを優先することです。データベースに対して最適に機能するコードは、多くの場合、アプリケーション開発者にとって醜いものです。
時期尚早の最適化についてのナンセンスを信じています。データベースは、元の設計とその後の開発におけるパフォーマンスを考慮する必要があります。私の意見では、パフォーマンスはデータベース設計の50%(40%はデータの整合性、最後の10%はセキュリティ)です。実際にユーザーと実際のトラフィックがデータベースに対して配置されると、実行するためにボトムアップで構築されていないデータベースのパフォーマンスが低下します。時期尚早の最適化は、最適化がないという意味ではありません!それはあなたがそれが簡単であると思うのでほとんどいつも悪いパフォーマンスをするコードを書くべきだという意味ではありません(例えば、他のすべてが失敗しない限り、本番データベースでは許可されるべきでないカーソル)。つまり、必要になるまで、最後の少しのパフォーマンスを絞り出すことを検討する必要はありません。データベースでのパフォーマンスが向上することについては多くのことが知られていますが、
パラメータ化されたクエリを使用しません。SQLインジェクションの停止に非常に便利です。
これは、別の回答で言及されている、入力データをサニタイズしない具体的な例です。
開発者がネストされた選択ステートメントを使用したり、クエリの「SELECT」部分内の選択ステートメントの結果を返す関数を使用したりするのは嫌です。
@adamにも同様の問題が指摘されていますが、ここでは他の場所でこれを見たことがないことに本当に驚いています。おそらく見落としました。
例:
SELECT
(SELECT TOP 1 SomeValue FROM SomeTable WHERE SomeDate = c.Date ORDER BY SomeValue desc) As FirstVal
,(SELECT OtherValue FROM SomeOtherTable WHERE SomeOtherCriteria = c.Criteria) As SecondVal
FROM
MyTable c
このシナリオでは、MyTableが10000行を返す場合、最初のクエリとその他の各テーブルのクエリを結果の行ごとに1回ずつ実行する必要があるため、クエリは20001クエリを実行したかのようになります。
開発者は、数行のデータのみを返し、サブテーブルには通常少量のデータしかない開発環境でこれを回避できますが、本番環境では、この種のクエリは指数関数的にコストがかかる可能性があります。データがテーブルに追加されます。
より良い(必ずしも完璧ではない)例は次のようなものです:
SELECT
s.SomeValue As FirstVal
,o.OtherValue As SecondVal
FROM
MyTable c
LEFT JOIN (
SELECT SomeDate, MAX(SomeValue) as SomeValue
FROM SomeTable
GROUP BY SomeDate
) s ON c.Date = s.SomeDate
LEFT JOIN SomeOtherTable o ON c.Criteria = o.SomeOtherCriteria
これにより、データベースオプティマイザーは、メインテーブルの各レコードを再クエリするのではなく、データを一緒にシャッフルできます。通常、この問題が発生したコードを修正する必要がある場合、通常、クエリの速度が100%増加します。 CPUとメモリの使用量を同時に削減しながらより多く。
SQLベースのデータベースの場合:
正しいレベルの正規化を行っていません。データが重複していないこと、および必要に応じてデータを別のデータに分割していることを確認する必要があります。また、パフォーマンスに悪影響を与えるので、正規化にあまり従わないようにする必要があります。
1- where句の値に関数を不必要に使用し、そのインデックスの結果が使用されていない
例:
where to_char(someDate,'YYYYMMDD') between :fromDate and :toDate
の代わりに
where someDate >= to_date(:fromDate,'YYYYMMDD') and someDate < to_date(:toDate,'YYYYMMDD')+1
そして、より少ない程度に:それらを必要とするそれらの値に機能インデックスを追加しない...
2-データの有効性を保証するためにチェック制約を追加しません。制約はクエリオプティマイザーで使用できます。制約は、不変条件を信頼できることを確認するのに役立ちます。それらを使用しない理由はありません。
3-純粋な怠惰または時間のプレッシャーからテーブルに正規化されていない列を追加します。物事は通常、このように設計されていませんが、これに発展します。最終結果は、間違いなく、将来の進化で失われたデータの整合性に悩まされたときに、混乱を解消しようとする膨大な作業です。
このことを考えてみてください。データのないテーブルは、再設計するのが非常に安価です。整合性のない数百万のレコードを持つテーブル...再設計するのにそれほど安くはありません。したがって、列またはテーブルを作成するときに正しい設計を行うと、スペードで償却されます。
4-データベース自体についてはそれほどではありませんが、実際に迷惑です。SQLのコード品質を気にしません。SQLがテキストで表現されているからといって、文字列操作アルゴリズムのヒープにロジックを隠しても問題ありません。同僚のプログラマーが実際に読み取り可能な方法でSQLをテキストで書くことは完全に可能です。
これは以前に言われましたが、 インデックス、インデックス、インデックスです。パフォーマンスの低いエンタープライズWebアプリの多くのケースを見て、小さなプロファイリング(ヒットしたテーブルを確認する)を行い、それらのテーブルにインデックスを追加するだけで修正されました。これはSQLを書くための知識をあまり必要とせず、その見返りは莫大です。
ペストのようなデータの重複を避けてください。一部の人々は、少しの複製が害を及ぼすことはなく、パフォーマンスを向上させると主張しています。ちょっと、スキーマが非常に抽象的で、DBAでさえ何が起こっているのかわからなくなるまで、スキーマを第3正規形に拷問する必要があるとは言っていません。一連の名前、郵便番号、または配送コードを複製すると、コピーは最終的に相互に同期しなくなることを理解してください。それは起こります。そして、毎週のメンテナンススクリプトを実行するときに、自分をキックするでしょう。
そして最後に:明確で一貫した直感的な命名規則を使用します。適切に記述されたコードが読み取り可能であるのと同じように、優れたSQLスキーマまたはクエリは読み取り可能であり、コメントがなくても実際に何が行われているかを伝える必要があります。テーブルのメンテナンスが必要な6か月後に感謝します。 "SELECT account_number, billing_date FROM national_accounts"
「SELECT ACCNTNBR、BILLDAT FROM NTNLACCTS」よりもはるかに簡単に操作できます。
私が20年間で見た最も一般的な間違い:事前に計画を立てていない。多くの開発者は、データベースとテーブルを作成し、アプリケーションを構築しながら、テーブルを継続的に変更および拡張します。最終結果は、多くの場合、混乱して非効率になり、後でクリーンアップまたは単純化することが困難になります。
a)クエリ値を文字列にハードコーディングする
b)Windowsフォームアプリケーションの "OnButtonPress"アクションにデータベースクエリコードを配置する
両方見ました。
スコットウォルツによる「クラシックデータベース開発の間違いとそれを克服するための5つの方法」と呼ばれるビデオへのリンクを次に示します。
DBMSが内部でどのように機能するかを理解していません。
クラッチのしくみを理解しないと、スティックを正しく動かすことはできません。そして、実際にハードディスク上のファイルに書き込んでいるだけであることを理解せずに、データベースの使い方を理解することはできません。
具体的には:
クラスタ化インデックスとは何か知っていますか?スキーマを設計するときにそれについて考えましたか?
インデックスを適切に使用する方法を知っていますか?インデックスを再利用するには?カバリングインデックスとは何かご存知ですか。
すばらしいですね。インデックスがあります。インデックスの1行はどのくらいの大きさですか?大量のデータがある場合、インデックスはどのくらい大きくなりますか?それは簡単にメモリに収まりますか?そうでない場合は、インデックスとしては役に立ちません。
MySQLでEXPLAINを使用したことがありますか?すごい。自分に正直に言ってください。見たものの半分でも理解できましたか?いいえ、おそらくしませんでした。修正してください。
クエリキャッシュを理解していますか?クエリをキャッシュできない理由を知っていますか?
MyISAMを使用していますか?全文検索が必要なら、とにかくMyISAMはくだらない。Sphinxを使用します。次に、Innoに切り替えます。