3

まず、この質問は MySQL 3.23.58 に関するものですので、ご注意ください。

次の定義を持つ2つのテーブルがあります。

Table A: id INT (primary), customer_id INT, offlineid INT

Table B: id INT (primary), name VARCHAR(255)

現在、テーブル A には 65,000 件以上のレコードが含まれ、テーブル B には最大 40 件のレコードが含まれています。2 つの主キー インデックスに加えて、テーブル A のofflineidフィールドにもインデックスがあります。各テーブルにはさらに多くのフィールドがありますが、このクエリには関係ありません (必要に応じて確認してください)。

最初に次のクエリが表示されました (クエリ時間: ~22 秒):

SELECT b.name, COUNT(*) AS orders, COUNT(DISTINCT(a.kundeid)) AS leads
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

現在、medie の各 ID は異なる名前に関連付けられています。つまり、名前だけでなく ID でもグループ化できます。少しテストを行ったり来たりして、これに落ち着きました(クエリ時間:〜6秒):

SELECT a.name, COUNT(*) AS orders, COUNT(DISTINCT(b.kundeid)) AS leads
FROM medie a
INNER JOIN katalogbestilling_katalog b ON a.id = b.offline
GROUP BY b.offline;

「瞬時」の時間 (最悪の場合、最大 1 秒) まで下げる方法はありますか? オフラインIDにインデックスを追加したのですが、それとクエリの並び替え以外にどうしたらいいのか途方に暮れています。EXPLAIN クエリは、クエリが fileshort を使用していることを示しています (元のクエリも一時テーブルを使用していました)。すべての提案を歓迎します!

4

9 に答える 9

1

あなたの主な問題は、古いバージョンの MySQL を使用していることだと思います。おそらく、MySQL 3 は COUNT(DISTINCT()) を好まないでしょう。

あるいは、単にシステム パフォーマンスである可能性もあります。どのくらいのメモリを持っていますか?

それでも、MySQL 3 は本当に古いです。新しいバージョンがそのクエリをより速く実行するかどうかを確認するために、少なくともテスト システムをまとめます。

于 2008-09-22T11:36:28.603 に答える
1

残念ながら、mysql 3 はサブクエリをサポートしていません。一般的に、古いバージョンがパフォーマンスの低下の原因であると思われます。

于 2008-09-22T12:10:34.557 に答える
0

内部結合を削除してネストされたselectステートメントに置き換えると、パフォーマンスがわずかに向上する可能性があります。また、count(*)を削除してPKに置き換えます。

SELECT a.name, COUNT(*) AS orders, COUNT(DISTINCT(b.kundeid)) AS leads FROM medie aINNER JOIN katalogbestilling_katalog b ON a.id = b.offline GROUP BY b.offline;

だろう

SELECT a.name, COUNT(a.id) AS orders, (SELECT COUNT(kundeid) FROM katalogbestilling_katalog b WHERE b.offline = a.id) AS Leads FROM medie a;

于 2008-09-22T11:57:24.557 に答える
0

2番目のクエリは問題なく、65k + 40k行はそれほど大きくありません:)

katalogbestilling_katalog.offline 列に新しいインデックスを配置すると、実行速度が向上します。

于 2008-09-22T13:17:05.600 に答える
0

サーバー自体を最適化してみてください。最も重要な変数については、Peter Zaitsev によるこの投稿を参照してください。InnoDB 固有のものもあれば、MyISAM 用のものもあります。この場合に関連する可能性のある使用しているエンジンについては言及していません (たとえば、count(*) は InnoDB よりも MyISAM の方がはるかに高速です)。 同じブログからの別の投稿と、 MySQL Forgeからの記事を次に示します。

于 2008-09-22T16:54:33.237 に答える
0

クエリがオーバーヘッドを保証するのに十分な頻度で実行される場合は、クエリで使用されるフィールドを含むテーブル A にインデックスを作成します。その後、すべての結果をインデックスから読み取ることができ、テーブルをスキャンする必要はありません。

とはいえ、私の経験はすべて MSSQL に基づいているため、うまくいかない可能性があります。

于 2008-09-22T12:12:49.327 に答える
0

クンデイドはどのように定義されていますか?上記のクエリを使用した EXPLAIN の出力だけでなく、両方のテーブルの完全なスキーマ (MySQL によって生成された、つまりインデックス付き) を確認すると役立ちます。

これをデバッグしてボトルネックを見つける最も簡単な方法は、クエリからフィールドを 1 つずつ削除し、実行にかかる時間を測定することです (各クエリを実行する前に RESET QUERY CACHE を実行することを忘れないでください)。ある時点で、実行時間が大幅に短縮され、ボトルネックが特定されます。例えば:

SELECT b.name, COUNT(*) AS orders, COUNT(DISTINCT(a.kundeid)) AS leads
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

なれるかもしれない

SELECT b.name, COUNT(DISTINCT(a.kundeid)) AS leads
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

「注文」がボトルネックになる可能性を排除するため、または

SELECT b.name, COUNT(*) AS orders
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

等式から「リード」を排除します。これはあなたを正しい方向に導きます。

update : 最終クエリからデータを削除することはお勧めしません。ボトルネックを探しながら変数の数を減らすために、それらを削除するだけです。あなたのコメントを見て、私は理解しています

SELECT b.name
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

まだパフォーマンスが悪いのですか?これは明らかに、最適化されていない結合またはグループ化 (グループ化を削除することでテストできます) であることを明確に意味します。結合は依然として遅く、その場合は修正が必要な問題であるか、そうでないかのいずれかです。 - その場合、それは明らかに GROUP BY です)。の出力を投稿できますか

EXPLAIN SELECT b.name
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

テーブルスキーマと同様に(デバッグを容易にするため)?

アップデート #2

すべてのインデックスが正しく作成されている可能性もありますが、最大メモリ使用量またはディスクソートの使用を強制するそれらの行に沿った何かに関しては、mysql のインストールが誤って構成されています。

于 2008-09-22T11:37:15.510 に答える
0

各テーブルにカバリング インデックスが定義されていることを確認してみてください。カバリング インデックスは、選択で要求された、または結合で使用された各列がインデックスに含まれている単なるインデックスです。このように、エンジンはインデックス エントリを読み取るだけでよく、インデックスに含まれていない要求された列を取得するために、対応する行のルックアップも行う必要はありません。私はこの手法を使用して、Oracle と MS SqlServer で大きな成功を収めました。

クエリを見て、次を試すことができます。

medie.id、medie.name の 1 つのインデックスkatalogbestilling_katalog.offlineid、katalogbestilling_katalog.kundeid
の 1 つのインデックス

列は、インデックスのこれらの順序で定義する必要があります。これにより、インデックスを使用できるかどうかが異なります。

詳細はこちら:

カバーインデックス情報

于 2008-09-22T14:59:36.040 に答える
0

(offlineid, kundeid) にインデックスを追加してみる

180,000 BS 行を katalog に追加し、30,000 BS 行を medie に追加しました (カタログの offlineid は medie id に対応し、いくつかの重複する kundeid を使用して、disinct カウントが確実に機能するようにします)。これはmysql 5上にあることに注意してください。同様の結果が得られない場合、mysql 3が原因である可能性がありますが、覚えていることから、mysql 3はこれをうまく処理できるはずです。

私のテーブル:

CREATE TABLE `katalogbestilling_katalog` (
  `id` int(11) NOT NULL auto_increment,
  `offlineid` int(11) NOT NULL,
  `kundeid` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `offline_id` (`offlineid`,`kundeid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=60001 ;

CREATE TABLE `medie` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=30001 ;

私のクエリ:

SELECT b.name, COUNT(*) AS orders, COUNT(DISTINCT(a.kundeid)) AS leads
FROM medie b
INNER JOIN katalogbestilling_katalog a ON b.id = a.offlineid
GROUP BY a.offlineid
LIMIT 0 , 30


"Showing rows 0 - 29 (30,000 total, Query took 0.0018 sec)"

そして説明:

id:  1
select_type:    SIMPLE
table: a
type: index
possible_keys:  NULL
key:    offline_id
key_len:    8
ref: NULL
rows: 180000
Extra: Using index

id: 1
select_type:    SIMPLE
table: b
type: eq_ref
possible_keys:  PRIMARY
key:    PRIMARY
key_len:    4
ref: test.a.offlineid
rows: 1
Extra:
于 2008-09-22T15:13:53.057 に答える