0

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 句はありませんが、実行速度が遅くなります。

私にとって、これは問題がクエリの複雑さではなく、結果の行サイズに関連してヒットしている制限であることを確認しています。

編集 - さらに調査した結果、問題はクエリに起因するものではないようです。わずかに異なる構成のデータベースで実行すると、これは問題になりません。

4

1 に答える 1

0

結合条件で where 句の一部を使用しようとする場合があります。

例えば

select a.*, b.* from a inner join b on a.col1 = b.col1 and b.status = 1 and a.status = 1
于 2013-04-04T12:09:58.477 に答える