2017-10-18 43 views
-1

我試圖做一個鏈接交換腳本,並遇到一些麻煩。 每個鏈接都可以通過一個IP地址x次訪問(鏈接表中的頻率)。每次看病收費(在鏈接表中給出的極限支出上限)一些信貸多個選擇的Mysql查詢導致高CPU負載

我有以下表格:

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行。

問題是,無論何時在表中約有200k行控制器CPU負載是巨大的。

應用由@Barmar提供的解決方案後:上 新增綜合指數(uniqueLink,IP)和滴速PRIMARY以外的所有其他指標,講解使我這個:

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 
+0

它是正確的,'總和(學分)'不使用'其中IP =「$ ip''? – Barmar

+0

@Barmar。這是正確的,總和(信用)不使用WHERE ip ='$ ip' –

+0

這是一個安全噩夢 – Strawberry

回答

1

嘗試使用一個連接,而不是相關的子查詢。

SELECT l.* 
FROM links AS l 
LEFT JOIN (
    SELECT uniqueLink, SUM(ip = '$ip') AS ip_visits, SUM(credits) AS total_credits 
    FROM contor 
    GROUP BY uniqueLink 
) AS c 
ON c.uniqueLink = l.unique AND ip_visits <= frequency AND total_credits <= limit 

如果這沒有幫助,請嘗試在contor.ip上添加索引。

+0

謝謝@Barmar連接似乎減少了對服務器的負載。然而..你有52298個查詢,其中一個連接不能使用索引正確 控制指標的Contor: PRIMARY KEY('key'), KEY'contor_IX1'('uniqueLink','credits','ip') 指數鏈接: PRIMARY KEY('unique'), KEY'unique'('unique','frequency','limit'), –

+0

'(uniqueLink,ip)'上的複合索引可能有幫助。 – Barmar

+0

評論中沒有格式,不可能閱讀。 – Barmar

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 
         ) 

那些相關子查詢要每個你的午餐。還有你的飯盒。

我建議測試一個內嵌視圖,在一次執行中執行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` ; 

EDIT

由於我們有一個保證contor.key柱爲非空(即約束條件爲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 
+0

#1064 - 您的SQL語法錯誤;檢查對應於您的MySQL服務器版本的手冊,以便在第11行的'ON l.frequency> = d.count_key AND l.limit> = d.sum_credits LIMIT 0,30'附近使用正確的語法 服務器版本:5.5。 54-0 + deb7u1-log(Debian) –

+0

* DOH!*。第二個「ON」關鍵字應該用「AND」關鍵字替換。 (更正適用於SQL中的答案。) – spencer7593

+0

現在我明白了睡眠剝奪的影響。僅在咖啡因和薯片上使用72小時:)謝謝@ spencer7593 –