【问题标题】:Delete with multiple where clauses extremely slow使用多个 where 子句删除非常慢
【发布时间】:2014-09-29 21:27:28
【问题描述】:

我运行一个 php/mysql 应用程序来帮助管理学区的信息。我有一个“学生”表,我每晚都会根据 SFTP 发送到我的服务器的信息使用 CRON 作业更新它。

该作业解析发送的 csv 文件中的数据,并将数据插入名为“students_temp”的表中。然后我将students_temp与students进行比较,删除数据匹配的行,更新存在但已更改信息的学生,并插入新学生。

该作业大约需要 380 秒才能完成,其中 97% 的时间用于 DELETE 语句。下面是两个表和删除语句,我不得不想象问题出在多个 where 子句上,但我不知道如何解决它。

学生

student_id  int(11)
student_ts  timestamp
student_local_id    varchar(100)
student_nj  bigint(11)
student_first   varchar(250)
student_last    varchar(250)
student_grade   int(11)
student_school  int(11)
student_district    int(11)
student_gender  varchar(1)
student_eth_american_indian int(1)
student_eth_asian   int(1)
student_eth_black   int(1)
student_eth_hispanic    int(1)
student_eth_pacific int(1)
student_eth_white   int(1)
student_status  int(1)
student_contact_name    text
student_address text
student_city    text
student_state   text
student_zip varchar(30)

Students_Temp

student_temp_id int(11)
student_temp_ts timestamp
student_temp_local_id   varchar(100)
student_temp_nj bigint(11)
student_temp_first  varchar(250)
student_temp_last   varchar(250)
student_temp_grade  int(11)
student_temp_grade_code varchar(255)
student_temp_school int(11)
student_temp_school_code    varchar(255)
student_temp_district   int(11)
student_temp_gender varchar(1)
student_temp_eth_american_indian    int(1)
student_temp_eth_asian  int(1)
student_temp_eth_black  int(1)
student_temp_eth_hispanic   int(1)
student_temp_eth_pacific    int(1)
student_temp_eth_white  int(1)
student_temp_status int(1)
student_temp_contact_name   text
student_temp_address    text
student_temp_city   text
student_temp_state  text
student_temp_zip    varchar(30)

SQL 删除语句

DELETE st FROM students_temp st
    INNER JOIN students s ON student_temp_local_id=student_local_id
    WHERE student_temp_nj=student_nj 
    AND student_temp_first=student_first 
    AND student_temp_last=student_temp_last
    AND student_temp_grade=student_grade
    AND student_temp_school=student_school
    AND student_temp_district=student_district
    AND student_temp_gender=student_gender
    AND student_temp_eth_american_indian=student_eth_american_indian
    AND student_temp_eth_asian=student_eth_asian
    AND student_temp_eth_black=student_eth_black
    AND student_temp_eth_hispanic=student_eth_hispanic
    AND student_temp_eth_pacific=student_eth_pacific
    AND student_temp_eth_white=student_eth_white
    AND student_temp_status=student_status
    AND student_temp_contact_name=student_contact_name
    AND student_temp_address=student_address
    AND student_temp_city=student_city
    AND student_temp_state=student_state
    AND student_temp_zip=student_zip;

【问题讨论】:

  • 它们(WHERE 中使用的字段)是否都已编入索引?
  • 如果您的表有索引,那么这些索引需要在每个删除语句中进行修改。您可以考虑删除删除的索引,然后再重建它们
  • 该表有多少行,是使用InnoDB还是MyISAM存储引擎?
  • 我认为我没有索引(外键?)设置。学生表大约有 25k,更新大约在 18-20k。我不确定在哪里可以找到有关存储引擎的答案。
  • 我认为不是where 子句让它变慢,而是inner join

标签: php mysql sql sql-server


【解决方案1】:

首先,您用于连接表的字段应该被索引(student_local_id 和 student_temp_local_id)。如果这些字段是标识符,则创建唯一索引。如果它们没有被索引,那么对于第一个表中的每一行,您都在扫描另一个表中的所有行。 只需添加索引即可加快您的流程。

其次,没有必要从 temp_table 中删除未修改的行来更新其他行。您可以只更新已修改的行,并插入学生中不存在的行

你可以这样做来更新

update table students a join students_temp b on b.student_temp_local_id=a.student_local_id
set a.field1 = b.field1, a.field2 = b.field2, ...
where a.field1 <> b.field1 or a.field2 <> b.filed2 or...

并插入新的

insert into students (field1, field2, ...)
    select field1, field2, ...
    from students_temp a
    where not exists (select 1 from students where student_local_id = a.student_temp_local_id);

【讨论】:

  • 似乎在 tostudent_local_id 字段上添加索引可以将脚本上的事务时间从 New Relic 报告的大约 385,000 毫秒提高到 5,700 毫秒!!
【解决方案2】:

似乎在 tostudent_local_id 字段中添加索引可以将脚本上的事务时间从大约 385,000 毫秒提高到 5,700 毫秒!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-23
    • 2012-04-23
    • 1970-01-01
    • 2014-08-07
    • 2018-07-09
    • 1970-01-01
    • 2011-10-25
    • 1970-01-01
    相关资源
    最近更新 更多