MySql 查询不使用索引集

标签 mysql optimization indexing mysql-5.7 percona-xtradb-cluster

最近,我们将数据库从 MariaDB 10.2 切换到 Percona Server (Mysql 5.7),并且我们有一个查询需要大约 15 秒(之前约为 0.5 秒),因为查询优化器未在主表上使用任何索引。因为应用逻辑,我们无法改变查询格式,我们需要让DB使用索引。

查询结构很简单:

EXPLAIN SELECT `clients`.`id` AS `t0_c0`,
       `client`.`name1` AS `t0_c1`,
       `client`.`name2` AS `t0_c2`,
       `users`.`id` AS `t1_c0`,
       `users`.`suffix` AS `t1_c1`,
       `users`.`position` AS `t1_c2`,
       `users`.`first_name` AS `t1_c3`,
       `users`.`last_name` AS `t1_c4`,
       `privateData`.`id` AS `t2_c0`,
       `privateData`.`first_name` AS `t2_c1`,
       `privateData`.`last_name` AS `t2_c2`,
       `tariff`.`id` AS `t3_c0`,
       `tariff`.`provider_id` AS `t3_c1`,
       `tariff`.`tariff_type` AS `t3_c2`,
       `tariff`.`name` AS `t3_c3`,
       `providers`.`id` AS `t4_c0`,
       `providers`.`name1` AS `t4_c1`,
       `providers`.`name2` AS `t4_c2`,
       `addresses`.`id` AS `t5_c0`,
       `addresses`.`zipcode` AS `t5_c1`,
       `addresses`.`country` AS `t5_c2`,
       `addresses`.`city` AS `t5_c3`,
       `private`.`id` AS `t6_c0`,
       `private`.`first_name` AS `t6_c1`,
       `private`.`last_name` AS `t6_c2`,
       `commercial`.`id` AS `t7_c0`,
       `commercial`.`name1` AS `t7_c1`,
       `commercial`.`name2` AS `t7_c2`,
       `commercial`.`name_on_invoice` AS `t7_c3`,
       `commercial`.`organization_type` AS `t7_c4`,
       `organizations`.`id` AS `t8_c0`,
       `organizations`.`person_id` AS `t8_c1`,
       `organizations`.`address_id` AS `t8_c2`,
       `organizations`.`status` AS `t8_c3`,
       `shaddresses`.`id` AS `t9_c0`,
       `shaddresses`.`zipcode` AS `t9_c1`,
       `shaddresses`.`country` AS `t9_c2`,
       `shaddresses`.`city` AS `t9_c3`,
       `shprivate`.`id` AS `t10_c0`,
       `shprivate`.`first_name` AS `t10_c1`,
       `shprivate`.`last_name` AS `t10_c2`,
       `coraddresses`.`id` AS `t11_c0`,
       `coraddresses`.`zipcode` AS `t11_c1`,
       `coraddresses`.`country` AS `t11_c2`,
       `corprivate`.`id` AS `t12_c0`,
       `corprivate`.`first_name` AS `t12_c1`,
       `corprivate`.`last_name` AS `t12_c2`,
FROM `client` `client`
LEFT OUTER JOIN `users` `users` ON (`client`.`user_id`=`users`.`id`)
AND (users.status!=5)
LEFT OUTER JOIN `private` `privateData` ON (`users`.`person_id`=`privateData`.`id`)
LEFT OUTER JOIN `tariff` `tariff` ON (`client`.`rate_id`=`tariff`.`id`)
LEFT OUTER JOIN `providers` `providers` ON (`client`.`provider_id`=`providers`.`id`)
LEFT OUTER JOIN `addresses` `addresses` ON (`client`.`main_address_id`=`addresses`.`id`)
LEFT OUTER JOIN `private` `private` ON (`client`.`main_person_id`=`private`.`id`)
LEFT OUTER JOIN `commercial` `commercial` ON (`client`.`main_organization_id`=`commercial`.`id`)
LEFT OUTER JOIN `organizations` `organizations` ON (`client`.`id_organization`=`organizations`.`id`)
AND (organizations.status!=5)
LEFT OUTER JOIN `addresses` `shaddresses` ON (`client`.`shipping_address_id`=`shaddresses`.`id`)
LEFT OUTER JOIN `private` `shprivate` ON (`client`.`shipping_person_id`=`shprivate`.`id`)
LEFT OUTER JOIN `addresses` `coraddresses` ON (`client`.`correspondense_address_id`=`coraddresses`.`id`)
LEFT OUTER JOIN `private` `corprivate` ON (`client`.`correspondense_person_id`=`corprivate`.`id`)
WHERE (client.status!=5)
ORDER BY client.id DESC
LIMIT 10
OFFSET 10

我可以更改任何索引,但是,我无法更改查询。 在旧主机上,它的运行时间为 0.2 秒,但是,它的优化器使用客户端表中的索引。使用 Percona Server (mysql 5.7) 需要 15 秒。优化器不使用客户端表中的任何索引。使用来自客户端表的 FORCE INCEX() 的时间将低于 1 秒(复合索引的时间约为 0.2 秒)。 表“providers”只有 1 行。 我已经在“客户”表上设置了索引,但是,在解释中,它们没有显示为可能的键。

我尝试将 MySql 变量“max_seeks_for_key”设置为 1,但是它仍然没有使用索引。

我认为我错过了一些基本的东西,但我不知道是什么。

此查询的解释是:

enter image description here

ORDER BY 正在生成临时表,并且正在使用所有资源(即使没有 INDEX,没有 order by 也会在一秒内运行)。

任何想法都会受到赞赏。

最佳答案

这应该比使用 FORCE 更有效:

SELECT  ...
    FROM ( SELECT  id
              FROM  client
              WHERE  status != 5
              ORDER BY  id DESC
              LIMIT  10 OFFSET 10 
          ) AS ids
    JOIN  client USING(id)
    LEFT OUTER JOIN  `users` `users`  ON (`client`.`user_id`=`users`.`id`)
      AND  (users.status!=5)
    LEFT OUTER JOIN  `private` `privateData`  ON (`users`.`person_id`=`privateData`.`id`)
    LEFT OUTER JOIN  `tariff` `tariff`  ON (`client`.`rate_id`=`tariff`.`id`)
    LEFT OUTER JOIN  `providers` `providers`  ON (`client`.`provider_id`=`providers`.`id`)
    LEFT OUTER JOIN  `addresses` `addresses`  ON (`client`.`main_address_id`=`addresses`.`id`)
    LEFT OUTER JOIN  `private` `private`  ON (`client`.`main_person_id`=`private`.`id`)
    LEFT OUTER JOIN  `commercial` `commercial`  ON (`client`.`main_organization_id`=`commercial`.`id`)
    LEFT OUTER JOIN  `organizations` `organizations`  ON (`client`.`id_organization`=`organizations`.`id`)
      AND  (organizations.status!=5)
    LEFT OUTER JOIN  `addresses` `shaddresses`  ON (`client`.`shipping_address_id`=`shaddresses`.`id`)
    LEFT OUTER JOIN  `private` `shprivate`  ON (`client`.`shipping_person_id`=`shprivate`.`id`)
    LEFT OUTER JOIN  `addresses` `coraddresses`  ON (`client`.`correspondense_address_id`=`coraddresses`.`id`)
    LEFT OUTER JOIN  `private` `corprivate`  ON (`client`.`correspondense_person_id`=`corprivate`.`id`)
    ORDER BY  client.id DESC -- Yes, repeated here 

关于MySql 查询不使用索引集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50319510/

相关文章:

algorithm - 具有 32/16 位除法的处理器上的 64/32 位除法

c++ - 埃拉托色尼筛 : bit wise optimized

mysql - 我的程序的数据库设计是否存在循环引用问题?

php - 使用 PDO 将文本区域 $_POST 发送到 MySQL

java - Swing:函数的执行顺序

python - 更改数据帧索引中的数字格式

indexing - Cassandra - 具有非主键缺点的 WHERE 子句

mysql - Sequelize.js 外键

mysql 查询不使用联合所有索引(Rows_sent : 115 Rows_examined: 1008)

indexing - 动态添加字段到 NutchDocument