PHPスクリプトによって生成されているMySQLクエリがあります。クエリは、次のようになります。
SELECT * FROM Recipe_Data WHERE 404_Without_200 = 0 AND Failures_Without_Success = 0 AND RHD_No IN (10, 24, 34, 41, 43, 51, 57, 59, 61, 67, 84, 90, 272, 324, 402, 405, 414, 498, 500, 501, 510, 559, 562, 595, 632, 634, 640, 643, 647, 651, 703, 714, 719, 762, 765, 776, 796, 812, 814, 815, 822, 848, 853, 855, 858, 866, 891, 920, 947, 956, 962, 968, 1049, 1054, 1064, 1065, 1070, 1100, 1113, 1119, 1130, 1262, 1287, 1292, 1313, 1320, 1327, 1332, 1333, 1335, 1340, 1343, 1344, 1346, 1349, 1352, 1358, 1362, 1365, 1482, 1495, 1532, 1533, 1537, 1549, 1550, 1569, 1571, 1573, 1574, 1596, 1628, 1691, 1714, 1720, 1735, 1755, 1759, 1829, 1837, 1844, 1881, 1919, 2005, 2022, 2034, 2035, 2039, 2054, 2076, 2079, 2087, 2088, 2089, 2090, 2091, 2092, 2154, 2155, 2156, 2157, 2160, 2162, 2164, 2166, 2169, 2171, 2174, 2176, 2178, 2179, 2183, 2185, 2186, 2187, 2201, 2234, 2236, 2244, 2245, 2250, 2255, 2260, 2272, 2280, 2281, 2282, 2291, 2329, 2357, 2375, 2444, 2451, 2452, 2453, 2454, 2456, 2457, 2460, 2462, 2464, 2465, 2467, 2468, 2469, 2470, 2473, 2474, 2481, 2485, 2487, 2510, 2516, 2519, 2525, 2540, 2545, 2547, 2553, 2571, 2579, 2580, 2587, 2589, 2597, 2602, 2611, 2629, 2660, 2662, 2700, 2756, 2825, 2833, 2835, 2858, 2958, 2963, 2964, 3009, 3090, 3117, 3118, 3120, 3121, 3122, 3123, 3126, 3127, 3129, 3130, 3133, 3135, 3137, 3138, 3139, 3141, 3142, 3145, 3146, 3147, 3151, 3152, 3155, 3193, 3201, 3204, 3219, 3221, 3222, 3223, 3224, 3225, 3226, 3227, 3228, 3229, 3231, 3232, 3233, 3234, 3235, 3237, 3239, 3246, 3250, 3253, 3259, 3261, 3291, 3315, 3328, 3377, 3381, 3383, 3384, 3385, 3387, 3388, 3389, 3390, 3396, 3436, 3463, 3465, 3467, 3470, 3471, 3484, 3507, 3515, 3554, 3572, 3641, 3672, 3683, 3689, 3690, 3692, 3693, 3694, 3697, 3698, 3705, 3711, 3713, 3715, 3716, 3717, 3719, 3720, 3722, 3726, 3727, 3732, 3737, 3763, 3767, 3770, 3771, 3772, 3773, 3803, 3810, 3812, 3816, 3846, 3847, 3848, 3851, 3874, 3882, 3902, 3903, 3906, 3908, 3916, 3924, 3967, 3987, 4006, 4030, 4043, 4045, 4047, 4058, 4067, 4107, 4108, 4114, 4115, 4131, 4132, 4133, 4137, 4138, 4139, 4140, 4141, 4142, 4146, 4150, 4151, 4152, 4153, 4157, 4158, 4160, 4163, 4166, 4167, 4171, 4179, 4183, 4221, 4225, 4242, 4257, 4435, 4437, 4438, 4443, 4446, 4449, 4450, 4451, 4452, 4454, 4460, 4550, 4557, 4618, 4731, 4775, 4804, 4972, 5025, 5026, 5039, 5042, 5294, 5578, 5580, 5599, 5602, 5649, 5726, 5779, 5783, 5931, 5934, 5936, 5939, 5940, 5941, 5978, 6044, 6056, 6113, 6116, 6118, 6122, 6123, 6125, 6127, 6128, 6129, 6130, 6131, 6135, 6141, 6145, 6147, 6150, 6152, 6153, 6154, 6160, 6166, 6169);
列RHD_Noはこのデータベースの主キーであり、合計で約400,000行あります。問題は、クエリが非常に遅く、多くの場合2秒程度ですが、10秒もかかることを確認しました。
クエリを説明しようとすると、すべて問題ないようです。
+----+-------------+-------------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | Recipe_Data | range | PRIMARY | PRIMARY | 4 | NULL | 420 | Using where |
+----+-------------+-------------+-------+---------------+---------+---------+------+------+-------------+
クエリをプロファイリングすると、次のようになります。
mysql> show profile;
+--------------------------------+----------+
| Status | Duration |
+--------------------------------+----------+
| starting | 0.000015 |
| checking query cache for query | 0.000266 |
| Opening tables | 0.000009 |
| System lock | 0.000004 |
| Table lock | 0.000006 |
| init | 0.000115 |
| optimizing | 0.000038 |
| statistics | 0.000797 |
| preparing | 0.000047 |
| executing | 0.000002 |
| Sending data | 2.675270 |
| end | 0.000007 |
| query end | 0.000003 |
| freeing items | 0.000071 |
| logging slow query | 0.000002 |
| logging slow query | 0.000058 |
| cleaning up | 0.000005 |
+--------------------------------+----------+
私は長い間この問題に取り組んできましたが、解決策を見つけることができませんでした。このクエリに明らかに問題があることはありますか? 420行を見るのに2秒以上かかるのかわかりません。
主キーで420行にアクセスしているため、おそらくインデックスアクセスパスになります。これにより、キーごとに2つのインデックスページと1つのデータページにアクセスできます。これらがキャッシュにある場合、クエリは高速に実行されます。そうでない場合、ディスクにアクセスするすべてのページに通常のディスク遅延が発生します。 5ミリ秒のディスク遅延と80%のキャッシュヒットを想定すると、420 3 * 0.2 * 5ms = 1.2秒に到達します。これは、表示されているオーダーです。
問題は、IN
が基本的にOR
sの束として扱われることです(例:.
col IN (1,2,3)
です
col = 1 OR col = 2 OR col = 3
これは、結合よりもかなり遅いです。
一時テーブルを作成し、「IN」句の値を入力して、その一時テーブルと結合するSQLコードを生成する必要があります。
CREATE TEMPORARY TABLE numbers (n INT)
次に、ループで、追加します
INSERT numbers VALUES ($next_number)
そして最後に
SELECT * FROM numbers, Recipe_Data
WHERE numbers.n = RHD_No
IN句をINNERJOIN句に変換する必要があります。
次のようなクエリを変換できます。
SELECT foo
FROM bar
WHERE bar.stuff IN
(SELECT stuff FROM asdf)
この他のようなクエリに:
SELECT b.foo
FROM (
SELECT DISTINCT stuff
FROM asdf ) a
JOIN bar b
ON b.stuff = a.stuff
あなたは多くのパフォーマンスを得るでしょう。
Phpがクエリを生成するときに、IN句内のアイテムの一時テーブルなどのトリックを試してください。 IN句は非常に時間がかかるため、可能であれば常に避けてください。
ここでギャンブルをし、次のクエリを1回だけ実行して、クエリに適したインデックスを作成すると、クエリ時間が少なくとも1秒短縮されることをお勧めします...
CREATE INDEX returnstatus ON Recipe_Data(404_Without_200,Failures_Without_Success)
参照: http://dev.mysql.com/doc/refman/5.0/en/create-index.html インデックスの作成、および http://dev.mysql.com /doc/refman/5.0/en/mysql-indexes.html クエリでのインデックスの使用方法。
それができない場合は、mysqlで実行中のすべてのプロセスを表示して、任意のソースから現在実行中のクエリが、サーバーのすべての時間を消費して強制終了するときに停止を拒否するかどうかを確認します。参照: http://dev.mysql.com/doc/refman/5.0/en/kill.html
それができない場合は、IN
ステートメントのID番号で各レコードを個別に参照する必要がないように、各レコードに共通する他の要素を特定してください。必要に応じて、その共通性を追跡するために別のテーブル列を追加します。次に、その共通性を持つ列を上記のインデックスに追加し、WHERE
ステートメントを使用する代わりに、IN
句でそれでフィルタリングします。たとえば、これらのID番号のみをページに印刷する場合は、タイプとしてvisible
列を指定します。tinyint
、値0
を除外し、値1
を検索結果に含めてから、visible
列をインデックスおよびWHERE
句に追加して、クエリ。そのIN
ステートメントはまったく必要ありません。
おそらく、in
ステートメントは、前のクエリを使用して動的に作成されます。その場合は、Recipe_Data WHERE 404_Without_200 = 0 AND Failures_Without_Success = 0
ですべての行をプルしてみてください。次に、PHPスクリプトで、RHD_No
が期待値と一致しない場合は、フェッチループ内のレコードを破棄するだけです。
SQlAlchemyを使用している私のような人にとっては、forループを使用することも良いオプションです。
rows=[]
for id in ids:
row = cls.query.filter(cls.id==id).first()
if row:
rows.append(row)
#return rows