PHP / MySQL - 每周更新7000万行

时间:2014-04-13 18:44:00

标签: php mysql sql

我的数据库中有超过7000万行。这些数据最初是从大约70,000个XML文件中解析和导入的。这些文件每周都会更新,因此我需要扫描这些XML文件(通过星期日凌晨2点的cron扫描)并更新已更改/插入新行的行。

$operatorSQL = "INSERT IGNORE INTO `operator` (`reference`, `national_operator_code`, `operator_code`, `operator_short_name`, `operator_name_on_license`, `trading_name`) VALUES (:reference, :nationalOperatorCode, :operatorCode, :operatorShortName, :operatorNameOnLicense, :tradingName);";
$serviceSQL = "INSERT IGNORE INTO `service` (`service_code`, `private_code`, `date_start`, `date_end`, `mode`, `description`, `origin`, `destination`) VALUES (:serviceCode, :privateCode, :dateStart, :dateEnd, :mode, :description, :origin, :destination);";
$serviceOperatorSQL = "INSERT IGNORE INTO `service_operator` (`service_code`, `operator_reference`) VALUES (:serviceCode, :operatorReference);";
$journeyPatternSQL = "INSERT IGNORE INTO `journey_pattern` (`reference`, `direction`, `destination_display`, `vehicle_type_code`, `vehicle_type_description`) VALUES (:reference, :direction, :destinationDisplay, :vehicleTypeCode, :vehicleTypeDescription);";
$journeyPatternRouteSQL = "INSERT IGNORE INTO `journey_pattern_route` (`journey_pattern_reference`, `route_reference`) VALUES (:reference, :routeReference);";
$journeyPatternSectionLink = "INSERT IGNORE INTO `journey_pattern_section_link` (`journey_pattern_reference`, `journey_pattern_section_reference`) VALUES (:reference, :journeyPatternSectionReference);";
$journeyPatternSectionSQL = "INSERT IGNORE INTO `journey_pattern_section` (`reference`) VALUES (:reference);";
$lineSQL = "INSERT IGNORE INTO `service_line` (`service_code`, `name`) VALUES (:serviceCode, :name);";
$timingLinkSQL = "INSERT IGNORE INTO `journey_pattern_timing_link` (`reference`, `stop_from`, `stop_from_timing`, `stop_from_sequence_number`, `stop_from_activity`, `stop_to`, `stop_to_timing`, `stop_to_sequence`, `stop_to_activity`, `run_time`, `direction`) VALUES (:reference, :stopFrom, :stopFromTiming, :stopFromSequenceNumber, :stopFromActivity, :stopTo, :stopToTiming, :stopToSequenceNumber, :stopToActivity, :runTime, :direction)";
$timingLinkJpsSQL = "INSERT INTO `journey_pattern_timing_link_jps` (`journey_pattern_timing_link`, `journey_pattern_section_reference`) VALUES (:linkReference, :sectionReference);";
$timingLinkRouteLinkRefSQL = "INSERT INTO `journey_pattern_timing_link_rlr` (`journey_pattern_timing_link`, `route_link_reference`) VALUES (:linkReference, :routeLinkReference);";
$routeSQL = "INSERT IGNORE INTO `route` (`reference`, `private_code`, `description`) VALUES (:reference, :privateCode, :description);";
$routeSectionSQL = "INSERT IGNORE INTO `route_section` (`reference`) VALUES (:reference);";
$routeLinkSQL = "INSERT IGNORE INTO `route_link` (`reference`, `stop_from`, `stop_to`, `direction`, `distance`) VALUES (:reference, :stopFrom, :stopTo, :direction, :distance);";
$routeLinkSectionSQL = "INSERT INTO `route_link_section` (`route_link_reference`, `route_section_reference`) VALUES (:routeLinkReference, :routeSectionReference);";
$vehicleJourneySQL = "INSERT IGNORE INTO `vehicle_journey` (`reference`, `private_code`, `departure`) VALUES (:reference, :privateCode, :departure);";
$vehicleJourneyServiceSQL = "INSERT IGNORE INTO `vehicle_journey_service` (`vehicle_journey_reference`, `service_reference`) VALUES (:reference, :serviceRef);";
$vehicleJourneyLineSQL = "INSERT IGNORE INTO `vehicle_journey_line` (`vehicle_journey_reference`, `service_line_reference`) VALUES (:reference, :lineRef);";
$vehicleJourneyJpSQL = "INSERT IGNORE INTO `vehicle_journey_jp` (`vehicle_journey_reference`, `journey_pattern_reference`) VALUES (:reference, :journeyPatternRef);";

以上是所有执行的SQL查询。您会注意到IGNORE语句中使用了INSERT子句,这只是为了确保如果任何文件有重复数据,没有错误会停止脚本,而只是忽略它它继续前进。

我觉得这是最有效的方式,但是当我在完成所有数据的初始插入后再次运行脚本时,它与原始插入的速度一样慢执行...肯定如果99.9%的行是相同的,它应该浏览?任何想法为什么会发生这种情况?

2 个答案:

答案 0 :(得分:2)

查询优化通常用于选择,更新和删除查询。您只是将数据插入表中这一事实意味着无法进行查询优化;引擎不必制定一些复杂的计划来将数据推送到表中。它进行插入的速度只是CPU,硬盘速度,I / O网络带宽以及其他因素的函数。您插入的数据在任何意义上都不会被缓存,因此如果您再次执行插入操作,它将以相同的速率完成。

答案 1 :(得分:0)

首先,我将确定性能问题是XML解析还是数据库。如果您运行程序但只是忽略对数据库的调用会发生什么 - 与数据库调用相比,它所花费的时间要少得多吗?

如果它是数据库我会做以下事情,如果合理地可能给出了数据的性质:

  1. 如果可能,将任务划分为数据的多次传递,每次传递代表一个表INSERT s。
  2. 在面向性能的数据结构中读取并缓存表中所有记录的足够关键信息,以便您可以执行"我是否有记录"检查内存。
  3. 对于输入中找到的每条记录,如果缓存内存检查表明您已经没有记录,则只发出INSERT语句。
  4. 如果您的密钥信息不大(例如整数键值),并且您没有在内存限制的盒子上运行,则可以执行此操作。否则,缓存的密钥可能不适合内存。如果是这种情况