PHPスクリプト内から実行するのに約0.11秒かかるかなり大きなクエリがあります(大規模ではありませんが、かなり頻繁に使用される可能性があります)が、phpmyadminを介して実行すると、クエリに0.0047秒かかると主張します。
私はかなりの調査を行い、返される列を最小限に減らすと(結果をソートするために使用される列を残して、〜50から2に)、クエリがはるかに高速になることがわかりました(phpmyadminと同じ領域内)請求)。残念ながら、これらの列のデータが必要です。返されたデータがエクスポートされる場合、(CSV として) 約 3k しかありません。order by 句を削除しても、影響はほとんどありません。
返される行数は非常に少ない (約 8 行) ため、phpmyadmin がデフォルトで使用する limit 句は問題になりません。
検索されるデータの量が (データ行のフェッチではなく) クエリに劇的な影響を与えるのは奇妙に思えます。
返される列を減らしたり、クエリを分割したりせずにパフォーマンスを向上させるために何ができるかわかりません (ボトルネックが変わるだけです)。
クエリは次のとおりです (これが明らかな問題にどの程度役立つかはわかりません)。
SELECT DISTINCT
f.MultiItemService,
b.GroupName,
n.CourierName,
f.DeliveryserviceId,
f.CourierId,
f.DeliveryserviceName,
f.CustomerDescription,
f.SageCode,
d.MarkupId,
d.Description AS MarkupDescription,
d.Discount,
d.FixedAmount,
f.Status,
f.MinItems,
f.MaxItems,
f.MinWeight,
f.MaxWeight,
f.MinVolume,
f.MaxVolume,
f.MinWidth,
f.MaxWidth,
f.MinHeight,
f.MaxHeight,
f.MinDepth,
f.MaxDepth,
f.MinWorth,
f.MaxWorth,
d.MinItems AS MarkupMinItems,
d.MaxItems AS MarkupMaxItems,
d.MinWeight AS MarkupMinWeight,
d.MaxWeight AS MarkupMaxWeight,
d.MinVolume AS MarkupMinVolume,
d.MaxVolume AS MarkupMaxVolume,
d.MinWidth AS MarkupMinWidth,
d.MaxWidth AS MarkupMaxWidth,
d.MinHeight AS MarkupMinHeight,
d.MaxHeight AS MarkupMaxHeight,
d.MinDepth AS MarkupMinDepth,
d.MaxDepth AS MarkupMaxDepth,
d.MinWorth AS MarkupMinWorth,
d.MaxWorth AS MarkupMaxWorth,
f.Price,
f.AdditionalPrice,
f.DeliveryType,
f.Consolidation,
f.Surcharge,
h.VatRate,
k.InsuranceLevelId,
k.InsuranceLevelDescription,
k.InsuranceLevelMinimum,
k.InsuranceLevelMaximum,
m.OptionId,
m.OptionDescription,
m.OptionCost,
f.CalculationId,
CASE b.GroupName WHEN 'home' THEN 1 WHEN 'customer' THEN 2 WHEN 'Standard' THEN 3 ELSE 4 END AS Priority
FROM users a
INNER JOIN groups b ON a.UserId = b.UserId AND a.ApiKey = 'ABC123ABC'
INNER JOIN markups d ON b.GroupId = d.GroupId
INNER JOIN markups_deliveryservices o ON d.MarkupId = o.MarkupId
INNER JOIN deliveryservices f ON o.DeliveryserviceId = f.DeliveryserviceId
INNER JOIN deliveryservices_days j ON f.DeliveryserviceId = j.DeliveryserviceId
INNER JOIN couriers n ON f.CourierId = n.CourierId
LEFT OUTER JOIN insurance_levels k ON f.DeliveryserviceId = k.DeliveryserviceId
LEFT OUTER JOIN optional_services_deliveryservices l ON f.DeliveryserviceId = l.DeliveryserviceId
LEFT OUTER JOIN optional_services m ON l.OptionId = m.OptionId
INNER JOIN deliveryservices_delivery_groups g ON f.DeliveryserviceId = g.DeliveryserviceId
INNER JOIN delivery_groups h ON g.DeliveryGroupId = h.DeliveryGroupId
INNER JOIN markups_delivery_groups p ON d.MarkupId = p.MarkupId
INNER JOIN delivery_groups q ON p.DeliveryGroupId = q.DeliveryGroupId
WHERE h.DeliveryGroupId IN (15,12)
AND q.DeliveryGroupId IN (15,12) AND f.DeliveryType = 'Business And Domestic'
AND a.Status = 1
AND b.Status = 1
AND d.Status = 1
AND n.Status = 1
AND f.Status = 1
AND 1 BETWEEN f.MinItems AND f.MaxItems
AND ((f.MultiItemService = 0 /* single parcel delivery services */
AND 32 BETWEEN f.MinWeight AND f.MaxWeight /* item total weight within limits */
AND 193960 BETWEEN f.MinVolume AND f.MaxVolume /* item total volume within limits */
AND 0 BETWEEN f.MinWorth AND f.MaxWorth) /* item total value within limits */
OR (f.MultiItemService = 1 /* multiple parcel delivery services */
AND 0.16 BETWEEN f.MinWeight AND f.MaxWeight /* max weight of any item within limits */
AND 969.8 BETWEEN f.MinVolume AND f.MaxVolume /* max volume of any item within limits */
AND 0 BETWEEN f.MinWorth AND f.MaxWorth /* max value of any item within limits */
AND ((32 != 0 AND 32 NOT BETWEEN f.MinWeight AND f.MaxWeight) /* item total weight NOT within limits */
OR (149200 != 0 AND 193960 NOT BETWEEN f.MinVolume AND f.MaxVolume) /* item total volume NOT within limits */
OR (0 != 0 AND 0 NOT BETWEEN f.MinWorth AND f.MaxWorth)
)))
AND 18.4 BETWEEN f.MinWidth AND f.MaxWidth
AND 15.6 BETWEEN f.MinHeight AND f.MaxHeight
AND 2.6 BETWEEN f.MinDepth AND f.MaxDepth
AND 1 BETWEEN d.MinItems AND d.MaxItems
AND 32 BETWEEN d.MinWeight AND d.MaxWeight
AND 193960 BETWEEN d.MinVolume AND d.MaxVolume
AND 18.4 BETWEEN d.MinWidth AND d.MaxWidth
AND 15.6 BETWEEN d.MinHeight AND d.MaxHeight
AND 2.6 BETWEEN d.MinDepth AND d.MaxDepth
AND 0 BETWEEN d.MinWorth AND d.MaxWorth
AND j.DayOfWeek = 5
AND j.UpToTime >= 61063
ORDER BY Priority
説明は次のとおりです。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE k system DeliveryserviceId NULL NULL NULL 0 const row not found
1 SIMPLE l system RuleId NULL NULL NULL 0 const row not found
1 SIMPLE m system PRIMARY NULL NULL NULL 0 const row not found
1 SIMPLE a ref PRIMARY,ApiKey ApiKey 257 const 1 Using where; Using temporary; Using filesort
1 SIMPLE q index PRIMARY PRIMARY 4 NULL 7 Using where; Using index; Using join buffer
1 SIMPLE p ref PRIMARY,DeliveryGroupId,MarkupId DeliveryGroupId 4 DeliveryApiAdv.q.DeliveryGroupId 2
1 SIMPLE d eq_ref PRIMARY,GroupId PRIMARY 4 DeliveryApiAdv.p.MarkupId 1 Using where
1 SIMPLE b eq_ref PRIMARY,UserId PRIMARY 4 DeliveryApiAdv.d.GroupId 1 Using where
1 SIMPLE o ref markup_id,DeliveryserviceId markup_id 4 DeliveryApiAdv.p.MarkupId 2 Using index
1 SIMPLE g ref PRIMARY,DeliveryGroupId,DeliveryserviceId PRIMARY 4 DeliveryApiAdv.o.DeliveryserviceId 1 Using where; Using index
1 SIMPLE h eq_ref PRIMARY PRIMARY 4 DeliveryApiAdv.g.DeliveryGroupId 1
1 SIMPLE j eq_ref PRIMARY PRIMARY 5 DeliveryApiAdv.o.DeliveryserviceId,const 1 Using where
1 SIMPLE f eq_ref PRIMARY,CourierId PRIMARY 4 DeliveryApiAdv.o.DeliveryserviceId 1 Using where
1 SIMPLE n eq_ref PRIMARY PRIMARY 4 DeliveryApiAdv.f.CourierId 1 Using where
編集 - さらに調査した後のフォローアップのビット。返される列の数を減らすと、実行時間が約 95% 劇的に短縮されます。これが発生するポイントは、使用される列によって異なります (つまり、約 12 個の INT 列に対して、約 8 個の適切なサイズの VARCHAR 列のみ)。実験では、CONCAT_WS を使用して SQL を実行し、返された列を個別に返すのではなく結合しました。これにより、返されるデータの列数が 11 から 22 に増加しました。
さらにデバッグするために、メインの SELECT を変更して、他のテーブルの ID フィールドのみを返すようにしましたが、結合はまったく変更しませんでした。次に、これを使用して一時テーブルを作成しました。これは急速に実行されます。次に、その一時テーブルをテーブルに結合して、実際に必要なデータを取得しました。このクエリには、主キーの非常に単純な結合があり、where 句はありませんが、実行速度が遅くなります。
私にとって、これは問題がクエリの複雑さではなく、結果の行サイズに関連してヒットしている制限であることを確認しています。
編集 - さらに調査した結果、問題はクエリに起因するものではないようです。わずかに異なる構成のデータベースで実行すると、これは問題になりません。