Mysql

Mysql Select vs Select SUM 性能

  • September 14, 2014

我需要檢查衝浪者是否已經投票這可以使用

方法一

Select record_num FROM table where etc etc.

IE

SELECT record_num
FROM content_votes_tmp 
WHERE up = 1
AND ip = INET_ATON('$_SERVER[REMOTE_ADDR]') 
AND content = $_POST[id]
AND UNIX_TIMESTAMP(datetime) > '$old_time'

方法二

Select Sum(votes) FROM table where etc etc.

IE

SELECT SUM(up) as up_count
FROM content_votes_tmp 
WHERE ip = INET_ATON('$_SERVER[REMOTE_ADDR]') 
AND content = $_POST[id]
AND UNIX_TIMESTAMP(datetime) > '$old_time'

使用儲存引擎作為 MyISAM ,表有大約 100 萬行,ROW 格式是靜態的。

我正在尋找性能更快的查詢。

那麼哪個查詢會更快?每次有人點擊“贊成”或“反對”按鈕時,都會觸發此查詢。,


這是一個表結構

CREATE TABLE IF NOT EXISTS `content_votes_tmp` (
 `up` int(11) NOT NULL DEFAULT '0',
 `down` int(11) NOT NULL DEFAULT '0',
 `ip` int(10) unsigned NOT NULL,
 `content` int(11) NOT NULL,
 `datetime` datetime NOT NULL,
 `is_updated` tinyint(2) NOT NULL DEFAULT '0',
 `record_num` int(11) NOT NULL AUTO_INCREMENT,
 PRIMARY KEY (`record_num`)
 KEY `content` (`content`),
 KEY `datetime` (`datetime`),
 KEY `is_updated` (`is_updated`),
 KEY `ip` (`ip`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=25 ;

您顯示的 2 個查詢的含義不同。

第一個將在該時間範圍內選擇該 IP 和內容的所有贊成票。如果創建索引:

mysql> ALTER TABLE content_votes_tmp ADD INDEX(up, ip, content, datetime, record_num);
Query OK, 753676 rows affected (3.85 sec)
Records: 753676  Duplicates: 0  Warnings: 0

您可以獲得良好的性能結果 - 將使用前 2 列,您將獲得 Using Index 優化:

mysql> EXPLAIN SELECT record_num 
              FROM content_votes_tmp  
              WHERE up = 1 AND 
                    ip = 1  AND 
                    content = 1 AND 
                    UNIX_TIMESTAMP(datetime) > @number\G
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: content_votes_tmp
        type: ref
possible_keys: up
         key: up
     key_len: 12
         ref: const,const,const
        rows: 1
       Extra: Using where; Using index
1 row in set (0.00 sec)

我們甚至可以做得更好。通過轉換 $old_time-刪除UNIX_TIMESTAMP()函式 -compare dates 而不是 int,並且能夠使用索引應用所有條件(3 個 consts 和 1 個範圍):

mysql> EXPLAIN SELECT record_num 
              FROM content_votes_tmp  
              WHERE up = 1 AND 
                    ip = 1  AND 
                    content = 1 AND 
                    datetime > now()\G
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: content_votes_tmp
        type: range
possible_keys: up
         key: up
     key_len: 17
         ref: NULL
        rows: 1
       Extra: Using where; Using index
1 row in set (0.00 sec)

如果應用程序的邏輯需要知道是否進行了否決,請小心,此查詢不會幫助您。

第二個需要稍微不同的索引:

mysql> ALTER TABLE content_votes_tmp ADD INDEX(ip, content, datetime, up);
Query OK, 753676 rows affected (5.95 sec)
Records: 753676  Duplicates: 0  Warnings: 0

為了得到一個好的查詢計劃,還需要“將函式移到操作數的另一邊”:

mysql> EXPLAIN SELECT SUM(up) as up_count 
      FROM content_votes_tmp  
      WHERE ip = 1 AND 
            content = 1 AND 
            datetime > now()\G
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: content_votes_tmp
        type: range
possible_keys: ip
         key: ip
     key_len: 13
         ref: NULL
        rows: 1
       Extra: Using where; Using index
1 row in set (0.00 sec)

我不喜歡 range + SUM(),所以我更喜歡第一個,它更簡單(除非你打算返回很多行)。但是查詢計劃中沒有任何東西可以支持我的恐懼(它也有覆蓋索引優化,並且沒有文件排序,所以使用適當的索引兩者都可以非常快 - 它們使用我的假 1M 數據需要 0.00 秒)。

請記住,邏輯略有不同,因此請注意 - 如果您允許贊成和反對,這可能是一個問題。

引用自:https://dba.stackexchange.com/questions/76500