提高 SQL 查询性能

埃布拉希米

我有一个复杂的查询,在我的机器上运行需要 700 毫秒。我发现瓶颈是ORDER BY at_firstname.value子句,但我如何使用索引来改进这一点?

SELECT 
    `e`.*
    , `at_default_billing`.`value` AS `default_billing`
    , `at_billing_postcode`.`value` AS `billing_postcode`
    , `at_billing_city`.`value` AS `billing_city`
    , `at_billing_region`.`value` AS `billing_region`
    , `at_billing_country_id`.`value` AS `billing_country_id`
    , `at_company`.`value` AS `company`
    , `at_firstname`.`value` AS `firstname`
    , `at_lastname`.`value` AS `lastname`
    , CONCAT(at_firstname.value
    , " "
    , at_lastname.value) AS `full_name`
    , `at_phone`.`value` AS `phone`
    , IFNULL(at_phone.value,"N/A") AS `telephone`
    , `e`.`entity_id` AS `id` 
FROM 
    `customer_entity` AS `e`  
LEFT JOIN 
    `customer_entity_int` AS `at_default_billing` 
    ON (`at_default_billing`.`entity_id` = `e`.`entity_id`) 
    AND (`at_default_billing`.`attribute_id` = '13')  
LEFT JOIN 
    `customer_address_entity_varchar` AS `at_billing_postcode` 
    ON (`at_billing_postcode`.`entity_id` = `at_default_billing`.`value`)        
    AND (`at_billing_postcode`.`attribute_id` = '30')  
LEFT JOIN 
    `customer_address_entity_varchar` AS `at_billing_city` 
    ON (`at_billing_city`.`entity_id` = `at_default_billing`.`value`) 
    AND (`at_billing_city`.`attribute_id` = '26')  
LEFT JOIN 
    `customer_address_entity_varchar` AS `at_billing_region` 
    ON (`at_billing_region`.`entity_id` = `at_default_billing`.`value`) 
    AND (`at_billing_region`.`attribute_id` = '28')  
LEFT JOIN 
    `customer_address_entity_varchar` AS `at_billing_country_id` 
    ON (`at_billing_country_id`.`entity_id` = `at_default_billing`.`value`) 
    AND (`at_billing_country_id`.`attribute_id` = '27')  
LEFT JOIN 
    `customer_address_entity_varchar` AS `at_company` 
    ON (`at_company`.`entity_id` = `at_default_billing`.`value`) 
    AND (`at_company`.`attribute_id` = '24')  
LEFT JOIN 
    `customer_entity_varchar` AS `at_firstname` 
    ON (`at_firstname`.`entity_id` = `e`.`entity_id`) 
    AND (`at_firstname`.`attribute_id` = '5')  
LEFT JOIN 
    `customer_entity_varchar` AS `at_lastname` 
    ON (`at_lastname`.`entity_id` = `e`.`entity_id`) 
    AND (`at_lastname`.`attribute_id` = '7')  
LEFT JOIN 
    `customer_entity_varchar` AS `at_phone` 
    ON (`at_phone`.`entity_id` = `e`.`entity_id`) 
    AND (`at_phone`.`attribute_id` = '136')  
ORDER BY 
    `at_firstname`.`value` ASC LIMIT 20

这是执行计划: 在此处输入图片说明

查询说明:

'1','SIMPLE','e',NULL,'ALL',NULL,NULL,NULL,NULL,'19951','100.00','Using temporary; Using filesort'
'1','SIMPLE','at_default_billing',NULL,'eq_ref','UNQ_CUSTOMER_ENTITY_INT_ENTITY_ID_ATTRIBUTE_ID,IDX_CUSTOMER_ENTITY_INT_ATTRIBUTE_ID,IDX_CUSTOMER_ENTITY_INT_ENTITY_ID,IDX_CUSTOMER_ENTITY_INT_ENTITY_ID_ATTRIBUTE_ID_VALUE','UNQ_CUSTOMER_ENTITY_INT_ENTITY_ID_ATTRIBUTE_ID','6','lazurd.e.entity_id,const','1','100.00',NULL
'1','SIMPLE','at_billing_postcode',NULL,'eq_ref','UNQ_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ATTRIBUTE_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_VALUE','UNQ_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID','6','lazurd.at_default_billing.value,const','1','100.00','Using where'
'1','SIMPLE','at_billing_city',NULL,'eq_ref','UNQ_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ATTRIBUTE_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_VALUE','UNQ_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID','6','lazurd.at_default_billing.value,const','1','100.00','Using where'
'1','SIMPLE','at_billing_region',NULL,'eq_ref','UNQ_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ATTRIBUTE_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_VALUE','UNQ_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID','6','lazurd.at_default_billing.value,const','1','100.00','Using where'
'1','SIMPLE','at_billing_country_id',NULL,'eq_ref','UNQ_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ATTRIBUTE_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_VALUE','UNQ_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID','6','lazurd.at_default_billing.value,const','1','100.00','Using where'
'1','SIMPLE','at_company',NULL,'eq_ref','UNQ_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ATTRIBUTE_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID,IDX_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_VALUE','UNQ_CUSTOMER_ADDRESS_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID','6','lazurd.at_default_billing.value,const','1','100.00','Using where'
'1','SIMPLE','at_firstname',NULL,'eq_ref','UNQ_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID,IDX_CUSTOMER_ENTITY_VARCHAR_ATTRIBUTE_ID,IDX_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID,IDX_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_VALUE','UNQ_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID','6','lazurd.e.entity_id,const','1','100.00',NULL
'1','SIMPLE','at_lastname',NULL,'eq_ref','UNQ_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID,IDX_CUSTOMER_ENTITY_VARCHAR_ATTRIBUTE_ID,IDX_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID,IDX_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_VALUE','UNQ_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID','6','lazurd.e.entity_id,const','1','100.00',NULL
'1','SIMPLE','at_phone',NULL,'eq_ref','UNQ_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID,IDX_CUSTOMER_ENTITY_VARCHAR_ATTRIBUTE_ID,IDX_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID,IDX_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_VALUE','UNQ_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID','6','lazurd.e.entity_id,const','1','100.00',NULL

表结构:

CREATE TABLE `customer_entity_varchar` (
  `value_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Value Id',
  `entity_type_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Entity Type Id',
  `attribute_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Attribute Id',
  `entity_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Entity Id',
  `value` varchar(255) DEFAULT NULL COMMENT 'Value',
  PRIMARY KEY (`value_id`),
  UNIQUE KEY `UNQ_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID` (`entity_id`,`attribute_id`),
  KEY `IDX_CUSTOMER_ENTITY_VARCHAR_ENTITY_TYPE_ID` (`entity_type_id`),
  KEY `IDX_CUSTOMER_ENTITY_VARCHAR_ATTRIBUTE_ID` (`attribute_id`),
  KEY `IDX_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID` (`entity_id`),
  KEY `IDX_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_VALUE` (`entity_id`,`attribute_id`,`value`),
  CONSTRAINT `FK_CSTR_ENTT_VCHR_ATTR_ID_EAV_ATTR_ATTR_ID` FOREIGN KEY (`attribute_id`) REFERENCES `eav_attribute` (`attribute_id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `FK_CSTR_ENTT_VCHR_ENTT_TYPE_ID_EAV_ENTT_TYPE_ENTT_TYPE_ID` FOREIGN KEY (`entity_type_id`) REFERENCES `eav_entity_type` (`entity_type_id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `FK_CUSTOMER_ENTITY_VARCHAR_ENTITY_ID_CUSTOMER_ENTITY_ENTITY_ID` FOREIGN KEY (`entity_id`) REFERENCES `customer_entity` (`entity_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=131094 DEFAULT CHARSET=utf8 COMMENT='Customer Entity Varchar';
穿刺者

截至目前,您的查询是:

  1. 首先执行所有左外连接。
  2. 然后ORDERing 行。
  3. 然后LIMITing 行。

我会首先执行严格需要的外连接,然后排序和限制(减少到 20 行),最后我会执行所有其余的外连接。简而言之,我会这样做:

  1. 首先执行最小左外连接。也就是说,只有两个表。
  2. 然后ORDERing 行。
  3. 然后LIMITing 行。这最多产生 20 行。
  4. 执行所有其余的外部联接。在这一点上,这不再是数千行,而是只有 20 行。

此更改应该会大大减少“唯一键查找”的执行次数。修改后的查询将如下所示:

select
  e.*
  , `at_default_billing`.`value` AS `default_billing`
  , `at_billing_postcode`.`value` AS `billing_postcode`
  , `at_billing_city`.`value` AS `billing_city`
  , `at_billing_region`.`value` AS `billing_region`
  , `at_billing_country_id`.`value` AS `billing_country_id`
  , `at_company`.`value` AS `company`
  , `at_lastname`.`value` AS `lastname`
  , CONCAT(firstname
  , " "
  , at_lastname.value) AS `full_name`
  , `at_phone`.`value` AS `phone`
  , IFNULL(at_phone.value,"N/A") AS `telephone`
from ( -- Step #1: joining customer_entity with customer_entity_varchar
SELECT 
    `e`.*
    , `at_firstname`.`value` AS `firstname`
    , `e`.`entity_id` AS `id` 
FROM 
    `customer_entity` AS `e`  
LEFT JOIN 
    `customer_entity_varchar` AS `at_firstname` 
    ON (`at_firstname`.`entity_id` = `e`.`entity_id`) 
    AND (`at_firstname`.`attribute_id` = '5')  
ORDER BY -- Step #2: Sorting (the bare minimum)
    `at_firstname`.`value` ASC 
LIMIT 20 -- Step #3: Limiting (to 20 rows)
) e
LEFT JOIN -- Step #4: Performing all the rest of outer joins (only few rows now)
    `customer_entity_int` AS `at_default_billing` 
    ON (`at_default_billing`.`entity_id` = `e`.`entity_id`) 
    AND (`at_default_billing`.`attribute_id` = '13')  
LEFT JOIN 
    `customer_address_entity_varchar` AS `at_billing_postcode` 
    ON (`at_billing_postcode`.`entity_id` = `at_default_billing`.`value`)        
    AND (`at_billing_postcode`.`attribute_id` = '30')  
LEFT JOIN 
    `customer_address_entity_varchar` AS `at_billing_city` 
    ON (`at_billing_city`.`entity_id` = `at_default_billing`.`value`) 
    AND (`at_billing_city`.`attribute_id` = '26')  
LEFT JOIN 
    `customer_address_entity_varchar` AS `at_billing_region` 
    ON (`at_billing_region`.`entity_id` = `at_default_billing`.`value`) 
    AND (`at_billing_region`.`attribute_id` = '28')  
LEFT JOIN 
    `customer_address_entity_varchar` AS `at_billing_country_id` 
    ON (`at_billing_country_id`.`entity_id` = `at_default_billing`.`value`) 
    AND (`at_billing_country_id`.`attribute_id` = '27')  
LEFT JOIN 
    `customer_address_entity_varchar` AS `at_company` 
    ON (`at_company`.`entity_id` = `at_default_billing`.`value`) 
    AND (`at_company`.`attribute_id` = '24')  
LEFT JOIN 
    `customer_entity_varchar` AS `at_lastname` 
    ON (`at_lastname`.`entity_id` = `e`.`entity_id`) 
    AND (`at_lastname`.`attribute_id` = '7')  
LEFT JOIN 
    `customer_entity_varchar` AS `at_phone` 
    ON (`at_phone`.`entity_id` = `e`.`entity_id`) 
    AND (`at_phone`.`attribute_id` = '136')  

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何提高sql查询的性能

来自分类Dev

通过 SQL Server 提高 SQL 查询的性能

来自分类Dev

SQL子查询性能需要提高

来自分类Dev

如何提高SQL Server Select查询的性能?

来自分类Dev

如何提高SQL Server Select查询的性能?

来自分类Dev

如何提高此SQL Server查询的性能?

来自分类Dev

如何提高SQL Azure查询性能

来自分类Dev

通过使用排序提高sql查询性能?

来自分类Dev

如何提高这个 sql 查询的性能?

来自分类Dev

提高 PHP 文件中的 SQL 查询性能

来自分类Dev

提高 SQL 查询选择性能

来自分类Dev

提高sql join count查询的性能

来自分类Dev

SQL提高性能

来自分类Dev

提高SQL性能

来自分类Dev

提高24小时返回相同结果的SQL查询的性能

来自分类Dev

使用嵌套循环提高SQL查询的性能-PostgreSQL

来自分类Dev

SQL查询需要提高的性能(1个表)

来自分类Dev

有可能提高此SQL查询的性能吗?

来自分类Dev

如何在SQL查询中提高多个联接表的性能

来自分类Dev

提高(查询)性能

来自分类Dev

提高LINQ查询性能?

来自分类Dev

提高SimpleMembership查询性能?

来自分类Dev

无法提高查询性能

来自分类Dev

提高查询性能

来自分类Dev

提高查询性能

来自分类Dev

提高子查询的性能

来自分类Dev

提高查询性能

来自分类Dev

SQL Server:如何提高WHERE子句中具有多个CTE和子查询的查询的性能

来自分类Dev

如何提高SQL查询的速度?