-1

リンク交換スクリプトを実行しようとしていますが、少し問題が発生します。各リンクは、IP アドレスによって x 回アクセスできます (リンク テーブルの頻度)。各訪問にはクレジット数がかかります (リンク テーブルの制限に指定されている使用制限)

次のテーブルがあります。

CREATE TABLE IF NOT EXISTS `contor` (
`key` varchar(25) NOT NULL,
`uniqueHandler` varchar(30) DEFAULT NULL,
`uniqueLink` varchar(30) DEFAULT NULL,
`uniqueUser` varchar(30) DEFAULT NULL,
`owner` varchar(50) NOT NULL,
`ip` varchar(15) DEFAULT NULL,
`credits` float NOT NULL,
`tstamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`key`),
KEY `uniqueLink` (`uniqueLink`),
KEY `uniqueHandler` (`uniqueHandler`),
KEY `uniqueUser` (`uniqueUser`),
KEY `owner` (`owner`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `links` (
`unique` varchar(30) NOT NULL DEFAULT '',
`url` varchar(1000) DEFAULT NULL,
`frequency` varchar(5) DEFAULT NULL,
`limit` float NOT NULL DEFAULT '0',
PRIMARY KEY (`unique`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

次のクエリがあります。

$link = MYSQL_QUERY("
    SELECT * 
    FROM `links` 
    WHERE (SELECT count(key) FROM contor WHERE ip = '$ip' AND contor.uniqueLink = links.unique) <= `frequency` 
    AND (SELECT sum(credits) as cost FROM contor WHERE contor.uniqueLink = links.unique) <= `limit`")

テーブル リンクには 20 行あります。

問題は、テーブル contor に約 200k 行がある場合は常に CPU 負荷が非常に大きくなることです。

@Barmar が提供するソリューションを適用した後: (uniqueLink, ip) に複合インデックスを追加し、PRIMARY を除く他のすべてのインデックスを削除すると、EXPLAIN は次のようになります。

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   PRIMARY     l   ALL     NULL    NULL    NULL    NULL    18  
1   PRIMARY     <derived2>  ALL     NULL    NULL    NULL    NULL    15  
2   DERIVED     pop_contor  index   NULL    contor_IX1  141     NULL    206122
4

2 に答える 2

1

現在のクエリの形式は次のとおりです。

 SELECT l.* 
   FROM `links` l
  WHERE l.frequency >= ( SELECT COUNT(ck.key)
                           FROM contor ck
                          WHERE ck.uniqueLink = l.unique
                            AND ck.ip = '$ip' 
                       )
    AND l.limit     >= ( SELECT SUM(sc.credits) 
                           FROM contor sc
                          WHERE sc.uniqueLink = l.unique 
                       )

これらの相関サブクエリは、それぞれのランチに送信されます。そしてあなたのお弁当も。

1 つのパスで両方の集計を実行するインライン ビューをテストし、contorその結果をテーブルに結合することをお勧めしlinksます。このようなもの:

 SELECT l.*
   FROM ( SELECT c.uniqueLink
               , SUM(c.ip = '$ip' AND c.key IS NOT NULL) AS count_key
               , SUM(c.credits)                          AS sum_credits
            FROM `contor` c
           GROUP
              BY c.uniqueLink
        ) d
   JOIN `links` l
     ON l.unique     = d.uniqueLink
    AND l.frequency >= d.count_key
    AND l.limit     >= d.sum_credits

集計インライン ビュー クエリのパフォーマンスを最適化するには、MySQL が GROUP BY を最適化するために使用できるカバリング インデックスを提供します (ファイルソート操作の使用を回避します)。

  CREATE INDEX `contor_IX1` ON `contor` (`uniqueLink`, `credits`, `ip`) ;

そのインデックスを追加すると、uniqueLinkインデックスが冗長になるため、...

  DROP INDEX `uniqueLink` ON `contor` ;

編集

contor.key列が非 NULLであることが保証されているため(つまり、NOT NULL制約)、上記のクエリのこの部分は不要AND c.key IS NOT NULLであり、削除できます。key(上記のカバリング インデックスの定義からも列を削除しました。)

 SELECT l.*
   FROM ( SELECT c.uniqueLink
               , SUM(c.ip = '$ip')  AS count_key
               , SUM(c.credits)     AS sum_credits
            FROM `contor` c
           GROUP
              BY c.uniqueLink
        ) d
   JOIN `links` l
     ON l.unique     = d.uniqueLink
    AND l.frequency >= d.count_key
    AND l.limit     >= d.sum_credits
于 2017-10-18T21:44:51.277 に答える