定制的客户网格导致MySQL表扫描和文件存储速度变慢

定制的客户网格导致MySQL表扫描和文件存储速度变慢,mysql,magento,grid,indexing,Mysql,Magento,Grid,Indexing,Magento企业。1.10.1.1. 客户和地址的数据集是半大的(125k+),CSR通常位于该网格上(有时一次超过25个并发用户) 下面是在CustomerGrid.phpBlock文件中生成集合的代码片段。没有什么新奇或不寻常的,只是简单地向集合添加属性 $collection = Mage::getResourceModel('customer/customer_collection') ->addNameToSelect() ->addAttributeTo

Magento企业。1.10.1.1. 客户和地址的数据集是半大的(125k+),CSR通常位于该网格上(有时一次超过25个并发用户)

下面是在Customer
Grid.php
Block
文件中生成集合的代码片段。没有什么新奇或不寻常的,只是简单地向集合添加属性

$collection = Mage::getResourceModel('customer/customer_collection')
    ->addNameToSelect()
    ->addAttributeToSelect('email')
    ->addAttributeToSelect('group_id')
    ->addAttributeToSelect('prod_codes')
    ->addAttributeToSelect('last_called_date')
    ->addAttributeToSelect('time_zone')
    ->addAttributeToSelect('salesrep')
    ->addAttributeToSelect('do_not_call')
    ->addAttributeToSelect('club_member')
    ->addAttributeToSelect('call_back_date')
    ->addAttributeToSelect('marketing_code_outcome')
    ->joinAttribute('billing_postcode', 'customer_address/postcode', 'default_billing', null, 'left')
    ->joinAttribute('billing_city', 'customer_address/city', 'default_billing', null, 'left')
    ->joinAttribute('billing_telephone', 'customer_address/telephone', 'default_billing', null, 'left')
    ->joinAttribute('billing_region', 'customer_address/region', 'default_billing', null, 'left');

$this->setCollection($collection);
生成此查询,该查询行为异常,导致在客户网格中的加载时间过长:

SELECT 
    e . *,
    _table_prefix.value AS prefix,
    _table_firstname.value AS firstname,
    _table_middlename.value AS middlename,
    _table_lastname.value AS lastname,
    _table_suffix.value AS suffix,
    CONCAT(IF(_table_prefix.value IS NOT NULL AND _table_prefix.value != '',
                CONCAT(TRIM(_table_prefix.value), ' '),
                ''),
            TRIM(_table_firstname.value),
            IF(_table_middlename.value IS NOT NULL AND _table_middlename.value != '',
                CONCAT(' ', TRIM(_table_middlename.value)),
                ''),
            ' ',
            TRIM(_table_lastname.value),
            IF(_table_suffix.value IS NOT NULL AND _table_suffix.value != '',
                CONCAT(' ', TRIM(_table_suffix.value)),
                '')) AS name,
    _table_default_billing.value AS default_billing,
    _table_billing_postcode.value AS billing_postcode,
    _table_billing_city.value AS billing_city,
    _table_billing_telephone.value AS billing_telephone,
    _table_billing_region.value AS billing_region
FROM
    customer_entity AS e
        LEFT JOIN
    customer_entity_varchar AS _table_prefix ON (_table_prefix.entity_id = e.entity_id) AND (_table_prefix.attribute_id = '4')
        LEFT JOIN
    customer_entity_varchar AS _table_firstname ON (_table_firstname.entity_id = e.entity_id) AND (_table_firstname.attribute_id = '5')
        LEFT JOIN
    customer_entity_varchar AS _table_middlename ON (_table_middlename.entity_id = e.entity_id) AND (_table_middlename.attribute_id = '6')
        LEFT JOIN
    customer_entity_varchar AS _table_lastname ON (_table_lastname.entity_id = e.entity_id) AND (_table_lastname.attribute_id = '7')
        LEFT JOIN
    customer_entity_varchar AS _table_suffix ON (_table_suffix.entity_id = e.entity_id) AND (_table_suffix.attribute_id = '8')
        LEFT JOIN
    customer_entity_int AS _table_default_billing ON (_table_default_billing.entity_id = e.entity_id) AND (_table_default_billing.attribute_id = '13')
        LEFT JOIN
    customer_address_entity_varchar AS _table_billing_postcode ON (_table_billing_postcode.entity_id = _table_default_billing.value) AND (_table_billing_postcode.attribute_id = '29')
        LEFT JOIN
    customer_address_entity_varchar AS _table_billing_city ON (_table_billing_city.entity_id = _table_default_billing.value) AND (_table_billing_city.attribute_id = '25')
        LEFT JOIN
    customer_address_entity_varchar AS _table_billing_telephone ON (_table_billing_telephone.entity_id = _table_default_billing.value) AND (_table_billing_telephone.attribute_id = '30')
        LEFT JOIN
    customer_address_entity_varchar AS _table_billing_region ON (_table_billing_region.entity_id = _table_default_billing.value) AND (_table_billing_region.attribute_id = '27')
WHERE
    (e.entity_type_id = '1')
ORDER BY CONCAT(IF(_table_prefix.value IS NOT NULL AND _table_prefix.value != '',
            CONCAT(TRIM(_table_prefix.value), ' '),
            ''),
        TRIM(_table_firstname.value),
        IF(_table_middlename.value IS NOT NULL AND _table_middlename.value != '',
            CONCAT(' ', TRIM(_table_middlename.value)),
            ''),
        ' ',
        TRIM(_table_lastname.value),
        IF(_table_suffix.value IS NOT NULL AND _table_suffix.value != '',
            CONCAT(' ', TRIM(_table_suffix.value)),
            '')) desc
LIMIT 20 OFFSET 60
查询中的
EXPLAIN
显示,请注意表e中使用临时和使用文件排序的额外内容:

除了1.10.1版本的Magento本身的默认索引外,未修改任何索引。请参见此处的1.5.1(CE)结构:

这是别名表,称为e。扫描时:

CREATE TABLE `customer_entity` (
    `entity_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `entity_type_id` SMALLINT(8) UNSIGNED NOT NULL DEFAULT '0',
    `attribute_set_id` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0',
    `website_id` SMALLINT(5) UNSIGNED NULL DEFAULT NULL,
    `email` VARCHAR(255) NOT NULL DEFAULT '',
    `group_id` SMALLINT(3) UNSIGNED NOT NULL DEFAULT '0',
    `increment_id` VARCHAR(50) NOT NULL DEFAULT '',
    `store_id` SMALLINT(5) UNSIGNED NULL DEFAULT '0',
    `created_at` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
    `updated_at` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
    `is_active` TINYINT(1) UNSIGNED NOT NULL DEFAULT '1',
    PRIMARY KEY (`entity_id`),
    INDEX `FK_CUSTOMER_ENTITY_STORE` (`store_id`),
    INDEX `IDX_ENTITY_TYPE` (`entity_type_id`),
    INDEX `IDX_AUTH` (`email`, `website_id`),
    INDEX `FK_CUSTOMER_WEBSITE` (`website_id`),
    CONSTRAINT `FK_CUSTOMER_ENTITY_STORE` FOREIGN KEY (`store_id`) REFERENCES `core_store` (`store_id`) ON UPDATE CASCADE ON DELETE SET NULL,
    CONSTRAINT `FK_CUSTOMER_WEBSITE` FOREIGN KEY (`website_id`) REFERENCES `core_website` (`website_id`) ON UPDATE CASCADE ON DELETE SET NULL
)
所以问题是如何让这个查询执行得更好,而不导致创建和扫描临时表。


我不确定我可以索引什么来提高查询性能,我也不想在修改Magento的ORM上花太多功夫

我再也记不起可怕的Magento表结构了,但如果可能的话,您可以加快这样的速度:

仅选择所需每个条目的主ID(仅执行行消除和排序所需的联接)。然后,只使用以前的ID进行大连接和值选择。在这种情况下,看起来您可以消除所有的地址连接,这应该是一个很大的胜利


由于要排序的原始数据更少,而且以后在大连接中的数据更少,您将有相当大的速度。在其他系统中,我已经在中运行了>100秒的查询,我不熟悉Magento Enterprise,但从MySQL的角度来看,我会寻找一种方法来取代它

ORDER BY CONCAT(IF(_table_prefix.value IS NOT NULL AND _table_prefix.value != '',
            CONCAT(TRIM(_table_prefix.value), ' '),
            ''),
        TRIM(_table_firstname.value),
        IF(_table_middlename.value IS NOT NULL AND _table_middlename.value != '',
            CONCAT(' ', TRIM(_table_middlename.value)),
            ''),
        ' ',
        TRIM(_table_lastname.value),
        IF(_table_suffix.value IS NOT NULL AND _table_suffix.value != '',
            CONCAT(' ', TRIM(_table_suffix.value)),
            '')) desc

预先计算的值为
名称
。这将删除重复计算。

不确定您的情况是否正确,但

如果您使用\u table\u prefix.attribute\u id链接表,并且它是一个整数,那么请删除引号,否则mysql将在比较之前将整数字段中的所有值转换为字符串。这将导致文件排序

AND (_table_prefix.attribute_id = '4')
…将更改为

AND (_table_prefix.attribute_id = 4)

如果删除ORDERBY子句,解释返回什么?编辑:我运行了它。通过删除订单可以解决问题。在本例中,您是按前缀排序的。这上面有索引吗?在索引与名称进行比较时查看索引。但可能不容易修复。不确定当前EAV模型是否可以轻松修复此问题。将ORDER By更改为简单的“\u table\u firstname.value”会导致相同的表扫描。最好的解决方案是创建平面表格并更改网格以在其上搜索。最好的。。。不容易,谢谢你的回复。是的,我也注意到了,除了其他一些类似的查询没有order by子句,但是仍然会得到较慢的表扫描。会减慢查询速度的主要因素是添加联接,如果有其他方法可以使用,请尝试,它应该会大大提高性能,因为addjoin会极大地消耗MySQL的性能。(不要引用我的话,这是我的主管昨天对我说的)@A_Wheel_Monkey,谢谢你的回复。这样做意味着我必须修改Magento的ORM。
AND (_table_prefix.attribute_id = 4)