簡體   English   中英

我還有什么可以做的來優化這個MySQL查詢?

[英]Is there anything else I can do to optimize this MySQL query?

我有兩個表,表A有700,000項,表B有600,000項。 結構如下:

表A:

+-----------+---------------------+------+-----+---------+----------------+
| Field     | Type                | Null | Key | Default | Extra          |
+-----------+---------------------+------+-----+---------+----------------+
| id        | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment | 
| number    | bigint(20) unsigned | YES  |     | NULL    |                | 
+-----------+---------------------+------+-----+---------+----------------+

表B:

+-------------+---------------------+------+-----+---------+----------------+
| Field       | Type                | Null | Key | Default | Extra          |
+-------------+---------------------+------+-----+---------+----------------+
| id          | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment | 
| number_s    | bigint(20) unsigned | YES  | MUL | NULL    |                | 
| number_e    | bigint(20) unsigned | YES  | MUL | NULL    |                | 
| source      | varchar(50)         | YES  |     | NULL    |                |
+-------------+---------------------+------+-----+---------+----------------+

我正在嘗試使用以下代碼查找表B中是否存在表A中的任何值:

$sql = "SELECT number from TableA";
$result = mysql_query($sql) or die(mysql_error());

while($row = mysql_fetch_assoc($result)) {
        $number = $row['number'];
        $sql = "SELECT source, count(source) FROM TableB WHERE number_s < $number AND number_e > $number GROUP BY source";
        $re = mysql_query($sql) or die(mysql_error);
        while($ro = mysql_fetch_array($re)) {
                echo $number."\t".$ro[0]."\t".$ro[1]."\n";
        }
}

我希望查詢能夠快速進行,但是由於某種原因,查詢速度並不快。 我對選擇的解釋(特定值為“數字”)為我提供了以下內容:

mysql> explain SELECT source, count(source) FROM TableB WHERE number_s < 1812194440 AND number_e > 1812194440 GROUP BY source;
+----+-------------+------------+------+-------------------------+------+---------+------+--------+----------------------------------------------+
| id | select_type | table      | type | possible_keys           | key  | key_len | ref  | rows   | Extra                                        |
+----+-------------+------------+------+-------------------------+------+---------+------+--------+----------------------------------------------+
|  1 | SIMPLE      | TableB     | ALL  | number_s,number_e       | NULL | NULL    | NULL | 696325 | Using where; Using temporary; Using filesort | 
+----+-------------+------------+------+-------------------------+------+---------+------+--------+----------------------------------------------+
1 row in set (0.00 sec)

我可以從中得到什么優化嗎?

我嘗試為同一任務編寫存儲過程,但它似乎一開始就沒有起作用……它沒有給出任何語法錯誤……我嘗試運行了一天,但仍在運行感到奇怪。

CREATE PROCEDURE Filter() 
Begin 
  DECLARE number BIGINT UNSIGNED; 
  DECLARE x INT; 
  DECLARE done INT DEFAULT 0; 
  DECLARE cur1 CURSOR FOR SELECT number FROM TableA; 
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 
  CREATE TEMPORARY TABLE IF NOT EXISTS Flags(number bigint unsigned, count int(11)); 
  OPEN cur1; 
  hist_loop: LOOP 
    FETCH cur1 INTO number; 
    SELECT count(*) from TableB WHERE number_s < number AND number_e > number INTO x; 
    IF done = 1 THEN 
      LEAVE hist_loop; 
    END IF; 
    IF x IS NOT NULL AND x>0 THEN 
      INSERT INTO Flags(number, count) VALUES(number, x); 
    END IF; 
  END LOOP hist_loop; 
  CLOSE cur1;
END

您正在嘗試查找包含點的間隔。 使用B樹索引(大多數數據庫中的默認索引類型)的速度不是很快,但是R樹索引對於這種查詢將非常有效。 MySQL不允許您直接更改索引的類型,但是您可以通過使用GEOMETRY列類型來強制MySQL使用R-Tree。

Quassnoi他有關MySQL嵌套集的文章中對此進行了介紹 雖然並不完全相同,但非常相似。 文章引用:

還有一類任務需要搜索包含已知值的所有范圍:

 * Searching for an IP address in the IP range ban list * Searching for a given date within a date range 

和其他幾個。 通過使用MySQL的R-Tree功能可以改善這些任務

在我看來,您在number_enumber_s列上具有單獨的索引,可能是通過單獨的ADD INDEX(number_e)ADD INDEX(number_s)列創建的。

如果添加一個包含這兩個列的索引,則可能會獲得更好的性能,因為它們都在查詢中使用,並且MySQL顯然不選擇使用任何一個單列索引,從而判斷了整個表的掃描會更快(如果您的查詢跨越較大范圍的值,這種情況並不罕見)。

ALTER TABLE tblB ADD INDEX(number_s,number_e);

在那之后,您將不需要單獨的number_s索引,因為MySQL只能將您剛創建的索引用於對number_s查詢,因此您最好刪除該索引。

首先,我假設期望的輸出是將輸入位於number_e和number_s之間的所有“源”及其計數進行分組。

我對語法不滿意,但您可能會考慮在此處使用“ BETWEEN”子句,而不是使用小於/大於大於運算符進行顯式比較

編輯:Zombat所說的也適用; 索引也會有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM