重新为Magento编制索引时违反约束/复制关键点

重新为Magento编制索引时违反约束/复制关键点,magento,pdo,duplicates,constraints,zend-db,Magento,Pdo,Duplicates,Constraints,Zend Db,我正在使用Magento CE 1.6.2,我的重新索引(url_重写)有问题 当我截断核心url时,重写。。。第一次通过后端点击索引器,一切都很好,我的url重写存储在core_url_rewrites中。。。 但是如果我第二次启动索引器(不刷新表),我会得到一个重复键的错误 这是我的桌子的屏幕截图: 注意:UNQ_核心_URL_重写_ID_路径_是系统_存储_ID是索引键 我怎样才能找到问题的根源 第一次工作,但随后的重新索引失败似乎有点不寻常。您确定您使用的是InnoDB,并且您的MySQ

我正在使用Magento CE 1.6.2,我的重新索引(url_重写)有问题

当我截断核心url时,重写。。。第一次通过后端点击索引器,一切都很好,我的url重写存储在core_url_rewrites中。。。 但是如果我第二次启动索引器(不刷新表),我会得到一个重复键的错误

这是我的桌子的屏幕截图:

注意:UNQ_核心_URL_重写_ID_路径_是系统_存储_ID是索引键


我怎样才能找到问题的根源

第一次工作,但随后的重新索引失败似乎有点不寻常。您确定您使用的是InnoDB,并且您的MySQL设置正确吗?我会检查你的innodb缓存是否足够大,看看MySQL本身是否有任何错误。Magento利用InnoDB的事务查询,如果MySQL内存或空间不足,无法存储此类大型事务中准备好的查询,则可能会遇到问题

您得到的错误具有误导性,因为在第一次构建表时,在第一次重新索引时会捕获到重复的键。如果这是一个简单的数据问题,例如重复的SKU或不正确的类别层次结构,那么索引将在第一次尝试时失败

您可能还希望确保应用程序的MySQL用户有足够的权限在必要时刷新表。Magento想用核武器炸桌子;如果不能,它可能会尝试重新生成,从而导致重复密钥错误


我还将尝试
tail
您的
exception.log
文件,看看您是否可以获得堆栈跟踪并将其发布到这里。另外,尝试为MySQL库启用调试日志记录(您可以在
/lib/Varien/Db/Adapter/Pdo/MySQL.php
的第103行将
$\u debug
的默认值更改为
true
——您可能还希望将
$\u LogCallQueries
更改为true)。查看
$\u debugFile
以找到
tail

的路径这应该可以解决问题

复制核心文件:/app/code/core/Mage/Catalog/Model/Resource/Url.php 发送至:/app/code/local/Mage/Catalog/Model/Resource/Url.php

查找此函数:

public function saveRewriteHistory($rewriteData)
{
    $rewriteData = new Varien_Object($rewriteData);
    // check if rewrite exists with save request_path
    $rewrite = $this->getRewriteByRequestPath($rewriteData->getRequestPath(), $rewriteData->getStoreId());

    if ($rewrite === false) {
        // create permanent redirect
        $this->_getWriteAdapter()->insert($this->getMainTable(), $rewriteData->getData());
    }

    return $this;

}
替换为:

protected $_processedRewrites = array();   // add this to your class vars on top

public function saveRewriteHistory($rewriteData)
{
    $rewriteData = new Varien_Object($rewriteData);
    // check if rewrite exists with save request_path
    $rewrite = $this->getRewriteByRequestPath($rewriteData->getRequestPath(), $rewriteData->getStoreId());
    $data = $rewriteData->getData();

    $current = $data["id_path"]."_".$data["is_system"]."_".$data["store_id"];
    if ($rewrite === false && !in_array($current, $this->_processedRewrites)) {
        $this->_processedRewrites[] = $current;
        // create permanent redirect
        $this->_getWriteAdapter()->insert($this->getMainTable(), $rewriteData->getData());
    }

    return $this;
}
问题在于,在插入之前,函数检查DB以查看重写是否存在于core_url_rewrites中。这很好。但它使用以下属性进行检查: 请求路径,是系统,存储id

我们的问题是,某些行具有重复的id\u路径,但具有不同的请求\u路径。。。这很奇怪,不知道为什么不应该

但使用此替换功能,它还将检查id_路径之前是否已处理,如果是,则不会插入它。它解决了问题


但是,我们仍然不知道问题的根源

我发现db用户拥有正确的权限,我不喜欢更改核心代码,不管它是否移动到本地

从1.4升级到1.6后,在命令行重新索引后出现错误

php indexer.php -reindex catalog_url
An error occurred while saving the URL rewrite
已将与日志中的以下异常配对:-

exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'category/360-1-6' for key 'UNQ_CORE_URL_REWRITE_ID_PATH_IS_SYSTEM_STORE_ID'' in httpdocs/lib/Zend/Db/Statement/Pdo.php:228
我通过mysql运行以下查询来定位问题记录(注意查询与异常的关系),它显示这与已重命名的类别有关

QUERY: select * from core_url_rewrite where id_path =  "category/360";
我注意到这是一个类别url重写,product_id记录是0而不是NULL,我怀疑这就是问题所在,如果您有此问题,请查看您的情况是否相同,运行以下命令:

QUERY: select * from core_url_rewrite where product_id=0;
当我运行上面的查询时,它返回了一条记录,即问题记录

我找到的解决办法是删除问题记录

现在catalog_url reindex解决了一个问题

运行下面的查询将返回一条product_id为NULL的新记录,并表示新的URI路径。旧的URI会导致404,而不是它应该做的重定向

QUERY: select * from core_url_rewrite where id_path =  "category/360";
我认为这是一个单一的数据记录问题,可能是升级后的问题。我不同意更改URL.php或截断core_URL_重写是正确的

此后,我两次重建了catalog_url的索引,第三次是作为完整重新索引的一部分。全部返回:目录URL重写索引已成功重建


我已经记录了我的发现您的情况可能有所不同,但这有助于解释您如何找到问题并解决问题。

其他解决方案:-

截断core_url_重写表时,将丢失所有旧url键更改传播记录。我发现删除所有标记为“is_system”1的记录将保持这些旧url重定向,请使用查询:-

DELETE FROM `core_url_rewrite` WHERE `is_system` = 1;
这与截断表同时维护url更改传播或您可能创建的定制重定向具有相同的影响

正如艾伦·斯托姆所解释的那样:-

is_系统属性可能更准确地命名为is_canonical_rewrite_,用于_category_或_product_category_组合。也就是说,is_system是Magento设置的一个布尔标志,用于让自己知道哪些行是由Magento创建的系统级重写,并且当前表示特定实体的“主”URL(与重定向重写相反,重定向重写也是由系统创建的,但其is_system标志设置为false)。艾伦·斯托姆-

此外,如果可以将损坏范围缩小到产品或类别记录,则可以使用以下方法:-

维护类别重定向:-

DELETE FROM `core_url_rewrite` WHERE `is_system` = 1 AND `category_id` IS NOT NULL;
DELETE FROM `core_url_rewrite` WHERE `is_system` = 1 AND `product_id` IS NOT NULL;
维护产品重定向:-

DELETE FROM `core_url_rewrite` WHERE `is_system` = 1 AND `category_id` IS NOT NULL;
DELETE FROM `core_url_rewrite` WHERE `is_system` = 1 AND `product_id` IS NOT NULL;
总的来说,请记住,标记为is_system 1的所有记录都是由Magento根据产品或类别数据创建的,可以重新创建。标记为is_system 0的记录在其他任何地方都不存在,并且将永远丢失“死端”旧链接