4

複数のテーブルからデータをプルしようとしていますが、日時フィールドでORDER BYを使用すると、少なくとも10秒後に結果が返されますが、ORDER BYなしで同じクエリを実行すると、2秒未満の結果が返されます。

これは私の現在のクエリです

SELECT
ph.call_subject AS callSubject,
ac.account_name AS accountName,
DATE_FORMAT(ph.trigger_on, "%c/%e/%Y %h:%i %p") AS triggerOn,
ind.name AS industry,
cc.call_code_name AS callCode
FROM phone_calls AS ph
INNER JOIN accounts AS ac ON ph.account_id = ac.account_id
INNER JOIN industries AS ind ON ind.industry_id = ac.industry_id
INNER JOIN call_codes AS cc ON ph.call_code_id = cc.call_code_id
WHERE ac.status = 1 AND ph.status = 1 AND ph.owner_id = 1 AND ac.do_not_call = 0
AND ph.trigger_on BETWEEN '2012-11-19 00:00:00' AND '2013-03-19 23:59:59'
ORDER BY ph.trigger_on ASC LIMIT 0,1000

次のフィールドはすべてINT(11)UNSIGNED型です。

ph.account_id
ac.account_id
ind.industry_id
ac.industry_id
ph.call_code_id
cc.call_code_id
ph.owner_id

次のフィールドはすべてtinyint(1)タイプです。

ac.status 
ph.status
ac.do_not_call

このフィールドは日時タイプです

ph.trigger_on

アカウントには30万件のレコードがあり、phone_callsには​​500万件のレコードがあることに注意してください。このORDERBYをより速く実行するにはどうすればよいですか?すべてのwhere句フィールド、すべてのON句、およびph.trigger_onにインデックスが付けられていることに注意してください。MyIsamではなくInnoDBストレージエンジンを使用しています。

ありがとう

4

5 に答える 5

5

これを試してください:

  1. 列にインデックスを作成する(phone_calls.trigger_on, phone_calls.status, phone_calls.owner_id)それを呼び出すpcto

  2. FROM句を次のように変更します。

    FROM phone_calls AS ph FORCE INDEX (pcto)

これが理想です。それが機能しない場合は、コメントを追加してください。それが機能することが保証されている別の方法を提供し、必要なパフォーマンスの向上を提供します。

注意:クエリの「すべての」列にインデックスを作成することは重要ではありません(実際には効果がありません)。MySQLは、テーブルごとに1つのインデックスのみを使用できます(より正確には、テーブルエイリアスごとに)。あなたは私たちがあなたに言っているインデックスを構築する必要があります。

于 2013-03-20T10:12:49.223 に答える
3

5行の制限がある場合、順序がないと、クエリは他の条件に一致する最初の5行を取得できます。

ORDER BY句がある場合は、他の条件に一致するすべての行を調べて、最も低い5つを選択する必要があります。

于 2013-03-20T00:11:45.800 に答える
0

私の経験では、SQLクエリからパフォーマンスを得る最も速い方法は、それを複数のステップに単純化することです。一時テーブルを利用して、ステップごとの結合と操作の数を減らします(メモリを消費し、速度を上げます)。私は長い間MySQLを使用していないので、以下の構文エラーの可能性についてはご容赦ください。ただし、クエリを次のように書き直すことができます。

CREATE TEMPORARY TABLE scratch1 AS (
    SELECT
            ph.call_subject AS callSubject,
            ac.account_name AS accountName,
            DATE_FORMAT(ph.trigger_on, "%c/%e/%Y %h:%i %p") AS triggerOn,
            ac.industry_id,
            ph.call_code_id
    FROM
            phone_calls AS ph
            INNER JOIN accounts AS ac ON ph.account_id = ac.account_id
    WHERE   
            ac.status = 1 AND ph.status = 1 AND ph.owner_id = 1 AND ac.do_not_call = 0
            AND ph.trigger_on BETWEEN '2012-11-19 00:00:00' AND '2013-03-19 23:59:59' )

ALTER TABLE scratch1 ADD industry VARCHAR(255)
ALTER TABLE scratch1 ADD callCode VARCHAR(255)

UPDATE scratch1 s JOIN industries ind ON ind.industry_id = s.industry_id
SET s.industry = ind.name

UPDATE scratch1 s JOIN call_codes cc ON cc.call_code_id = s.call_code_id
SET s.callCode = cc.call_code_name

CREATE TEMPORARY TABLE scratch2 AS (
    SELECT * FROM scratch1 ORDER BY triggerOn ASC )

SELECT * FROM scratch2 LIMIT 0, 1000
于 2013-03-20T00:43:44.300 に答える
0

これは、Ersunのソリューション/コメントについて詳しく説明するためのものです。

がない場合order by、SQLはクエリを評価します。この場合、それは結合の束です。おそらく、結合フィールドにインデックスがあります。したがって、クエリは、からレコードを読み取り、phone_callsデータを検索し、フィルター条件をチェックして、それを返すことによって続行されます。その後、レコードなどに移動します。全体として、おそらく数千または数万のレコードを読み取ります。

を使用するorder byと、SQLはクエリ内のすべてのレコードを評価する必要があります。最後の電話が最小値である可能性があるため、すべての電話を読み取る必要があります。次に、並べ替えを行い、適切なレコードを返します。

phone_calls(status, owner_id, trigger_on)を満たすためにインデックスをオンにすることで、クエリを高速化できる場合があります。where

于 2013-03-20T00:51:32.487 に答える
0

(SELECT)akaでSELECTを実行すると、実際には一時テーブルで作業するようなものになります。以下の例では、1つのメインの大きなテーブルにいくつかの結合があります。このソリューションでは、クエリが0.2秒に短縮されましたが、ORDERBYがテーブルクエリ全体にある場合は20秒でした。

   SELECT * FROM (SELECT `cse_notes`.`notes_id`, `cse_notes`.`dateandtime`, 
    `cse_case`.`case_id`, `cse_case_notes`.`attribute`
    FROM  `cse_notes` 
    INNER JOIN  `cse_case_notes` 
    ON `cse_notes`.`notes_uuid` =  `cse_case_notes`.`notes_uuid`
    INNER JOIN `cse_case` 
    ON  `cse_case_notes`.`case_uuid` = `cse_case`.`case_uuid`
    WHERE `cse_notes`.`deleted` = 'N' AND `cse_case`.`case_id` = :case_id
    AND `cse_notes`.customer_id = :customer_id) notes
    ORDER BY `dateandtime` DESC

これは非常に遅く実行される悪いクエリです。フィルタリングを開始する前にテーブル全体を並べ替える必要があるとは思いもしませんでした。インデックス作成だけでは役に立ちませんでした。

    SELECT `cse_notes`.`notes_id`, `cse_notes`.`dateandtime`,
    `cse_case`.`case_id`, `cse_case_notes`.`attribute`    
    FROM  `cse_notes`     
    INNER JOIN  `cse_case_notes` ON `cse_notes`.`notes_uuid` =  `cse_case_notes`.`notes_uuid`    
    INNER JOIN `cse_case` ON  `cse_case_notes`.`case_uuid` = `cse_case`.`case_uuid`    
    WHERE `cse_notes`.`deleted` = 'N' 
    AND `cse_case`.`case_id` = :case_id    
    AND `cse_notes`.customer_id = :customer_id    
    ORDER BY `cse_notes`.dateandtime DESC LIMIT 0, 1000
于 2015-03-07T03:25:29.800 に答える