背景:
程序列表页展示信息,需后台多表关联读取视图,视图内sql已优化(索引、语句),外层增加查询条件后速度基本一致。
VIEW:
CREATE VIEW a
AS
SELECT *
FROM b FORCE INDEX (`idx_b`)
JOIN a ON a.CId = b.Id
JOIN c ON c.CId = b.Id
LEFT JOIN s ON s.No = c.No
LEFT JOIN d ON d.CId = a.Id AND d.EId = c.Id
LEFT JOIN e FORCE INDEX (`idx_e`) ON e.CId = a.Id
WHERE b.isdeleted = 0
环境:
1).mysql 5.7.10 InnoDB引擎 2核4G
2).阿里云RDS 4核8G (貌似效果更差<分片性能会衰减>)
问题:
1.外层增加排序order by条件后,速度变慢,查看执行计划为将试图内数据转化为temp_table后再进行sort;
2.直接count视图的话更加缓慢,已达不能接受地步,列表分页肯定需展示总条数,抛除视图,直接使用sql也是很缓慢。
大神们指点指点怎样优化mysql多表关联的count
巴扎黑2017-04-17 16:22:04
あなたが書いた SQL ステートメントに基づいて、いくつかの提案があります:
1. テーブル B は強制インデックスを使用して、テーブル エントリの数が多い場合、インデックス クエリが使用できない可能性があります。通常の状況では、データベースに選択させるだけで済みます。または、自分で検証し、isdeleted = 0 の条件を使用してテーブル b を確認し、force インデックスを使用した方がパフォーマンスが優れていることを確認します。そうでない場合は、force インデックスを削除します。
2. SQL ステートメントの数をカウントするには、テーブル a、b、および c のみを保持します。他のテーブルは、統計結果に影響しません。
3. 取得されたテーブル b のフィールドによる。前のステップで出力された主キー フィールドは、詳細情報を取得するために PHP でループされます。一般にページ数は少ないため、主キーを介してデータを複数回フェッチする方が高速になる場合があります。
また、みんなに分析してもらいたい場合は、SQLの実行計画を投稿するのがベストです。
PHP中文网2017-04-17 16:22:04
複数回クエリを実行し、それらを合計してレコードの総数を取得します。どうでしょうか? ? (未テスト....)
たとえば、各クエリのデータ量は 8000 レコードです
PHP 代码
:
迷茫2017-04-17 16:22:04
最終的にクエリするのはテーブル b のデータです。テーブル b をカウントする場合、なぜ他のテーブルを結合する必要があるのでしょうか? count はテーブル全体のスキャンであり、基本的に where を追加しない最適化方法はありません。
黄舟2017-04-17 16:22:04
当初の研究開発では、アイテムの総数を非同期でロードし、データとページ番号が最初に出力されるようにしていました。このように、意図的に数をチェックしない限り、その数は表示されません。大きな影響がありました。
その後、上記の提案を読んでビューを変更したところ、読み込みの総数も高速になりました。
また、ビューを使用するときに外部条件のインデックスを作成できるようにするために、これらの必須インデックスが追加されました。
この最適化は当面はまだ許容可能です。