2

私は、ローンのみで商品を販売する e ショップに取り組んでいます。任意のカテゴリでページごとに 10 個の製品を表示します。各製品には 3 つの異なる値札 (3 つの異なるローンの種類) があります。テスト時間中はすべてがうまくいき、クエリ実行時間は完璧でしたが、今日、変更を本番サーバーに転送すると、サイトは約 2 分で「崩壊」しました。ローンの種類を選択するために使用されるクエリは、10 秒程度ハングすることがあり、頻繁に発生するため、追いつくことができず、非常に遅くなります。データを格納するために使用されるテーブルには約 200 万のレコードがあり、各選択は次のようになります。

SELECT * 
FROM products_loans 
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24") 
AND 369.27 BETWEEN CENA_OD AND CENA_DO;

3 つのローン タイプと CENA_OD と CENA_DO の間の範囲内にある必要がある価格、したがって 3 行が返されます。

しかし、ページごとに 10 個の製品を表示する必要があるため、これに対する他の解決策が見つからなかったため、ORを使用して変更された選択を実行する必要があります。ここで質問しましたが、回答がありません。参照元の投稿で述べたように、結合で使用できる列がないため、これは個別に行う必要があります (もちろん、価格とコードを除きますが、非常にひどい結果に終わりました)。これはshow create table、kod および CENA_OD/CENA_DO で、INDEX によって非常に索引付けされています。

CREATE TABLE `products_loans` (
  `KOEF_ID` bigint(20) NOT NULL,
  `KOD` varchar(30) NOT NULL,
  `AKONTACIA` int(11) NOT NULL,
  `POCET_SPLATOK` int(11) NOT NULL,
  `koeficient` decimal(10,2) NOT NULL default '0.00',
  `CENA_OD` decimal(10,2) default NULL,
  `CENA_DO` decimal(10,2) default NULL,
  `PREDAJNA_CENA` decimal(10,2) default NULL,
  `AKONTACIA_SUMA` decimal(10,2) default NULL,
  `TYP_VYHODY` varchar(4) default NULL,
  `stage` smallint(6) NOT NULL default '1',
 PRIMARY KEY  (`KOEF_ID`),
 KEY `CENA_OD` (`CENA_OD`),
 KEY `CENA_DO` (`CENA_DO`),
 KEY `KOD` (`KOD`),
 KEY `stage` (`stage`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

また、すべてのローンの種類を選択し、後で php でフィルタリングしてもうまくいきません。各種類には 50,000 を超えるレコードがあり、選択にも時間がかかりすぎるためです...

速度の改善に関するアイデアは大歓迎です。

編集:

ここに説明があります

+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+
| id | select_type | table          | type  | possible_keys       | key  | key_len | ref  | rows   | Extra       |
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | products_loans | range | CENA_OD,CENA_DO,KOD | KOD  | 92      | NULL | 190158 | Using where |
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+

複合インデックスを試してみたところ、テスト サーバーのパフォーマンスが 0.44 秒から 0.06 秒に向上しました。ただし、自宅から運用サーバーにアクセスできないため、明日試してみる必要があります。

4

3 に答える 3

2

問題は、(間隔内のすべてのポイントのより通常のクエリではなく)ポイントを含む間隔を検索していることです。これらのクエリは、標準のBツリーインデックスではうまく機能しないため、代わりにRツリーインデックスを使用する必要があります。残念ながら、MySQLでは列のRツリーインデックスを選択できませんが、列タイプをGEOMETRYに変更し、幾何関数を使用して間隔にポイントが含まれているかどうかを確認することで、目的のインデックスを取得できます。

Quassnoiの記事「隣接リストと入れ子集合:MySQL 」を参照してください。彼はこれについて詳しく説明しています。ユースケースは異なりますが、関連する手法は同じです。記事の関連部分からの抜粋は次のとおりです。

既知の値を含むすべての範囲を検索する必要がある特定のクラスのタスクもあります。

  • IP範囲禁止リストでIPアドレスを検索する
  • 日付範囲内の特定の日付を検索する

と他のいくつか。これらのタスクは、MySQLのRツリー機能を使用することで改善できます。

于 2010-06-09T18:52:00.060 に答える
1

次のようにクエリをリファクタリングしてみてください。

SELECT * FROM products_loans 
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24") 
AND CENA_OD >= 369.27
AND CENA_DO <= 369.27;

(mysqlはインデックスを選択するときにあまり賢くありません)そしてパフォーマンスをチェックします。

次の試みは、結合されたキーを追加することです-(KOD、CENA_OD、CENA_DO)

そして次の主要な試みは、製品を価格から分離するためにベースをリファクタリングすることです。これは本当に役立つはずです。

PS:postgresqlに移行することもできます。適切なインデックスを選択する場合、mysqlよりも賢くなります。

于 2010-06-09T18:51:42.943 に答える
0

MySQLは1つのキーしか使用できません。常に3列のエントリを取得する場合、列の実際のデータ(範囲)に応じて、次のいずれかがかなりのパフォーマンスを追加する可能性があります。

ALTER TABLE products_loans ADD INDEX(KOD, CENA_OD, CENA_DO);
ALTER TABLE products_loans ADD INDEX(CENA_OD, CENA_DO, KOD);

列の順序が重要であることに注意してください。それでもパフォーマンスが向上しない場合EXPLAINは、クエリの出力を提供してください。

于 2010-06-09T18:52:36.543 に答える