MySql Query - 使用 varchars、索引进行优化,需要一个多小时才能运行

Posted

技术标签:

【中文标题】MySql Query - 使用 varchars、索引进行优化,需要一个多小时才能运行【英文标题】:MySql Query - optimization with varchars, indexs, taking over an hour to run 【发布时间】:2016-05-07 16:55:06 【问题描述】:

所以我需要运行一个我不知道 UUID 的查询 - 但需要找到它...所以我使用街道编号、街道名称和公司 UUID 来查找它

我有几百万条记录,这个耗时查询大约需要一个小时!!

有什么建议可以加快速度吗?

gisPoints
UUID  Indexed Unique    varchar(36)
street_num  int(11)
street_name varchar(128)

geoPoint_temp
UUID  Indexed Unique    varchar(36)
street_num  int(11)
street_name varchar(128)
gcomUUID Indexed    varchar(36)


update geoPoint_temp as temp JOIN gisPoints as `prod` on prod.gcomUUID=temp.gcomUUIDand prod.street_num=temp.street_num and prod.street_name REGEXP(temp.street_name)
        set temp.UUID=prod.UUID,temp.customerUUID=prod.customerUUID     WHERE temp.`uploadstate` = '1'";

【问题讨论】:

您的查询中发生了什么?我看到您正在执行更新,但是在什么表上?您是否正在执行 JOIN 操作以创建“临时表”,然后更新该临时表?还是您想更新已经存在的表? 我将 gisPoints 中的 UUID 插入到 geoPoint_temp 表中 我知道,但是当您执行 JOIN 操作时,您正在创建一个临时表。因此,如果我有例如SELECT a.ID, b.DATE FROM a JOIN b ON a.ID = b.ID,我将创建一个既不是a 也不是b 的表。因此,您的代码当前正在执行UPDATE (your join code) SET ...,您的连接代码正在创建一个临时表。你同意我更新的表是临时的吗? 好吧...有道理,我正在更新 geoPoint_temp,而不是临时表 您的表格是否正在更新?过了一小时后更新了吗? 【参考方案1】:

假设您有以下值(在 php 中):

$street_num  = ...;//something
$street_name = ...;//something
$gcomUUID = ...;//something

如果你运行下面的sql代码:

$sql = "SELECT * FROM (
    SELECT * FROM (
        SELECT * FROM geoPoint_temp WHERE gcomUUID = $gcomUUID) 
    WHERE street_name = $street_name)
WHERE street_num = $street_num;"

您应该从 geoPoint_temp 中获取具有匹配值的行列表(0 或更多),并且即使在大表中也应该相对较快。

获取这些行后,您可以检查行数是否大于零,如果是,则更新行。如果您使用 mysql (PDO),您可以执行类似以下操作:

$count = $stmt->rowCount();
if ($count>0)

  $rows = $stmt->fetchAll();
  foreach ($rows as $row)
  
    $sql = "UPDATE geoPoint_temp SET ... WHERE UUID = ".$row['UUID'];
    $stmt = $conn->prepare($sql);
    $stmt->execute();
  

如果有帮助,请告诉我。

已编辑:

尝试以下方法,如果有效,请告诉我:

$sql = "
UPDATE geoPoint_temp SET ... WHERE UUID IN 
    (SELECT * FROM (
        SELECT * FROM (
            SELECT * FROM geoPoint_temp WHERE gcomUUID = $gcomUUID) 
        WHERE street_name = $street_name)
    WHERE street_num = $street_num);"

并将... 替换为您要更新的值。

【讨论】:

我必须有一个额外的查询,然后做一个while循环遍历geoPoint_temp来填写street_num、street_name、gcomUUID。我想做的是让mysql做繁重的工作 我很确定 sql 可以完成所有这些,但我个人不确定如何为 UPDATE 查询编写条件。如果我将答案中的第一个 $sql 语句修改为以 $sql = "SELECT ID FROM ... 开头并保持所有其余部分相同,我实际上会有一列需要更新的 ID,但是在更新时,我不知道的是如何使用列编写 where 条件:UPDATE geoPoint_temp SET ... WHERE ???。我知道我们已经有一个需要比较 ID 的列,但是 sql 是否允许您比较 WHERE UUID = [column obtained] @morty346 很酷,如果可行,请告诉我你是如何做到的,我也有兴趣知道哈哈 @morty346 我已经用一个应该可以使用的选项更新了我的答案,如果可以,请告诉我。 在下面添加了我的 - 如果你想更新你的以反映变化,我很乐意选择你的作为答案 - 因为你让我们朝着正确的方向前进 - 再次感谢!【参考方案2】:

这运行时间为 1.5 秒,而之前需要几个小时 @Webeng 为我们指明正确的方向提供了很大帮助!

$custquery="UPDATE geoPoint_temp as temp
        join
        (
                        select prod.name, prod.street_num, prod.street_name, prod.UUID,prod.customerUUID, prod.gcomUUID 
                        FROM gisPoints as `prod`
                        JOIN
                        (
                                        select t1.gcomUUID , t1.street_num, t1.street_name
                                        FROM geoPoint_temp as t1
                        ) as sub1 on prod.gcomUUID =sub1.gcomUUID  and prod.street_num=sub1.street_num
        ) as sub2 on sub2.gcomUUID =temp.gcomUUID 
        and sub2.street_num=temp.street_num
        AND sub2.street_name LIKE (CONCAT('%',temp.street_name,'%'))
        set temp.customerUUID = sub2.customerUUID, temp.UUID=sub2.UUID";
        $custre=mysql_query($custquery);
        if (!$custre)     echo 'Could not run custre query: ' . mysql_error();    exit;    

【讨论】:

以上是关于MySql Query - 使用 varchars、索引进行优化,需要一个多小时才能运行的主要内容,如果未能解决你的问题,请参考以下文章

mysql_query()执行之后没有结果,MySQL数据库中数据表还为空

如何在 PHP 中使用 mysqli_query()?

Mysql Join Query需要很长时间才能执行

MYSQL创建表的时候如果加 索引

mysql varchar最大是多少?

mysql Error1093错误