【问题标题】:Restructure huge unnormalized mysql database part 2重构巨大的非规范化 mysql 数据库第 2 部分
【发布时间】:2012-09-25 13:15:42
【问题描述】:

我有一个大约 4 亿行的非规范化数据库,我已将所有重复数据移动到一个新的规范化数据库中,以便我可以用 id 来表示它。

现在我需要移动所有数据条目并将其转换为包含 id 的条目。

问题是 400m 行需要一段时间.. 我需要帮助来优化。

此查询每行需要 0.4 秒,因此需要几个月的时间:

INSERT IGNORE INTO normalized.entry (insDate, `date`, project, keyword, url, position, competition, serachEngine)
SELECT 
CURDATE() as insDate
, d.id as dateId
, p.id as projectId
, k.id as keywordId
, z.id AS urlId 
, old.position
, old.competition
, s.id as searchEngineId

FROM unnormalized.bigtable old
INNER JOIN normalized.`date` d  ON old.insDate = d.`date`
INNER JOIN normalized.project p ON old.awrProject = p.project
INNER JOIN normalized.searchEngine s ON old.searchEngine = s.searchEngine
INNER JOIN normalized.keyword k ON old.keyword = k.keyword
INNER JOIN normalized.urlHash z ON old.url = z.url
WHERE old.id >= ".$start." AND old.id <= ".$stop."";

如果我使用更多的 php 并将其分成两个查询,则以这种方式执行每个条目只需 0.07 秒,但这也需要几个月的时间:

$q = "SELECT tmp.id
              , d.id as dateId
              , p.id as projectId
              , k.id as keywordId
              , tmp.position
              , tmp.competition
              , s.id as searchEngineId
              , tmp.url
              , z.id AS urlId 
               FROM unnormalized.bigtable tmp
        INNER JOIN normalized.`date` d ON tmp.insDate = d.`date`
        INNER JOIN normalized.project p ON tmp.awrProject = p.project
        INNER JOIN normalized.searchEngine s ON tmp.searchEngine = s.searchEngine
        INNER JOIN normalized.keyword k ON tmp.keyword = k.keyword
        INNER JOIN normalized.urlHash z ON tmp.url = z.url
        WHERE tmp.id > ".$start." AND tmp.id < ".$stop."";
        // echo $q;
            $result = mysql_query($q, $local);
            if (mysql_num_rows($result) > 0) {
            while ($row = mysql_fetch_array($result)) {
            $q = "SELECT id FROM normalized.url WHERE url = '".$row["url"]."'";
            $resultUrl = mysql_query($q, $local);
            $rowUrl = mysql_fetch_array($resultUrl);

            $q = "INSERT IGNORE normalized.entry (insDate, `date`, project, keyword, url, position, competition, serachEngine) VALUES (NOW(), '".$row["dateId"]."', '".$row["projectId"]."', '".$row["keywordId"]."', '".$rowUrl["id"]."', '".$row["position"]."', '".$row["competition"]."', '".$row["searchEngineId"]."')";

如果不花半年时间,我不知道如何移植这些数据! /它需要的所有帮助

规范:我在 RDS 亚马逊服务器上使用 InnoDB。

编辑:第一个查询的 EXPLAIN SELECT:

id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra 1,SIMPLE,p,index,NULL,projectName,42,NULL,1346,"使用索引" 1,SIMPLE,s,index,NULL,searchEngine,42,NULL,2336,"使用索引;使用连接缓冲区" 1,SIMPLE,k,index,NULL,keyword,42,NULL,128567,"使用索引;使用连接缓冲区" 1,SIMPLE,tmp,ref,"keyword_url_insDate,keyword,searchEngine,url,awrProject",keyword_url_insDate,767,func,115,"使用哪里" 1,SIMPLE,d,eq_ref,date,date,3,intradb.tmp.insDate,1,"使用where;使用索引" 1,SIMPLE,z,ref,url,url,767,bbointradb.tmp.url,1,"使用索引"

显示创建表:

'rankingUrls201001', '创建表rankingUrls201001 ( id int(11) NOT NULL AUTO_INCREMENT, insDate 日期时间不为空, keyword varchar(255) 整理 utf8_swedish_ci 非空, searchEngine varchar(25) 整理 utf8_swedish_ci 非空, url varchar(255) 整理 utf8_swedish_ci 非空, position int(11) 非空, competition varchar(20) 整理 utf8_swedish_ci 非空, awrProject varchar(200) 整理 utf8_swedish_ci 非空, server varchar(20) 整理 utf8_swedish_ci 非空, rank varchar(40) 整理 utf8_swedish_ci 非空, 主键 (id), 键keyword_url_insDate (keyword,url,insDate), 键keyword (keyword), 键searchEngine (searchEngine), 键url (url), 键awrProject (awrProject) ) ENGINE=InnoDB AUTO_INCREMENT=2266575 DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci'

【问题讨论】:

  • 表的架构是什么? (SHOW CREATE TABLE your_table 的输出)
  • EXPLAIN your_select_query(您的问题中的第一个 INSERT 查询使用的 SELECT 查询)的输出是什么?
  • 我已将 EXPLAIN 的输出添加到帖子底部。
  • 将重复数据移动到另一个表中以便您可以用 id 号表示它,部分原因是为了增加您需要的连接数。它与标准化没有任何关系。 (没有“用 ID 号替换文本”范式这样的东西。)
  • 我知道,但是删除所有重复数据很好,我的目标是 3 范式。

标签: mysql database-design innodb database-schema amazon-rds


【解决方案1】:

@Robin,为了加快数据传输过程,您应该采取适当的步骤来确保所有处理都在内存中完成,并且您应该尽可能避免任何写入磁盘的操作。 如果您执行以下步骤,文件传输处理时间应该会减少:

  1. 首先,配置您的数据库实例以分配尽可能多的临时工作空间。

  2. 其次,将流程拆分为多步骤流程,这样每个处理阶段都会以最少的写入磁盘活动完成。

  3. 最后,禁用二进制日志;这将减少 WRITE 到磁盘的处理,在许多情况下可以将查询响应时间减少一半。

这些步骤应该会加快处理速度,但考虑到您拥有的数据行数量,传输和处理仍可能需要一定的时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-12
    • 2016-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    • 2011-12-16
    相关资源
    最近更新 更多