MySQL忽略索引,即使使用索引或强制索引

MySQL忽略索引,即使使用索引或强制索引,mysql,indexing,Mysql,Indexing,在这里,我将添加部分查询,因为它是敏感信息,我不会使用真实姓名: SELECT `entity`.`id`, `entity`.`requirements`, `entity`.`description`, `entity`.`status`, `entity_videos`.`length`, `entity_videos`.`quality`, `states`.`name`, `uploads`.`id`, `uploads`.`name` FR

在这里,我将添加部分查询,因为它是敏感信息,我不会使用真实姓名:

SELECT
  `entity`.`id`,
  `entity`.`requirements`,
  `entity`.`description`,
  `entity`.`status`,
  `entity_videos`.`length`,
  `entity_videos`.`quality`,
  `states`.`name`,
  `uploads`.`id`,
  `uploads`.`name`
    FROM  `entity`
    LEFT JOIN  `states`  ON `states`.`id` = `entity`.`state_id`
    INNER JOIN  `uploads` FORCE INDEX (`uploadable_id_index`)
       ON  `uploads`.`uploadable_type` = 'Entity'
      AND  `uploads`.`category` = 'Icon'
      AND  (`uploads`.`uploadable_id` = `entity`.`id`
              OR  `uploads`.`uploadable_id` = `entity`.`parent_entity_for_icon`
           )
    INNER JOIN  `entity_videos` FORCE INDEX (entity_videos_entity_id_index)
       ON `entity_videos`.`entity_id` = `entity`.`id`
    WHERE  `entity`.`status` = 'active' 
问题是Mysql优化器不想使用
uploadable\u id\u index
index。部分解释:

正如我所知,强制索引是强制优化器使用索引,除非优化器不能使用索引。我应该怎么做才能强制索引,而不是对表进行完全扫描? 我试图删除
entity\u videos\u entity\u id\u index
,还试图将
uploads
表信息添加到where子句,但没有任何效果。有什么想法吗?非常感谢你的帮助

更新:

在@Barmar和@PaulSpiegel的帮助下,我发现问题出在
(uploads.uploadable\u id=entity.id或uploads.uploadable\u id=entity.parent\u entity\u for\u icon)
。玩了一段时间的query之后,我发现在我的情况下,最好的解决方案是:

 SELECT
  `entity`.`id`,
  `entity`.`requirements`,
  `entity`.`description`,
  `entity`.`status`,
  `entity_videos`.`length`,
  `entity_videos`.`quality`,
  `states`.`name`,
  `icon`.`id`,
  `icon`.`name`,
  `parent_offer_icon`.`id`,
  `parent_offer_icon`.`name`
    FROM  `entity`
    LEFT JOIN  `states`  ON `states`.`id` = `entity`.`state_id`
    LEFT JOIN  `uploads` as `icon` FORCE INDEX (`uploadable_id_index`)
       ON  `icon`.`uploadable_type` = 'Entity'
      AND  `icon`.`category` = 'Icon'
      AND  `icon`.`uploadable_id` = `entity`.`id`
    LEFT JOIN  `uploads` as `parent_offer_icon` FORCE INDEX (`uploadable_id_index`)
       ON  `parent_offer_icon`.`uploadable_type` = 'Entity'
      AND  `parent_offer_icon`.`category` = 'Icon'
      AND  `parent_offer_icon`.`uploadable_id` = `entity`.`parent_entity_for_icon`
    INNER JOIN  `entity_videos` FORCE INDEX (entity_videos_entity_id_index)
       ON  `entity_videos`.`entity_id` = `entity`.`id`
    WHERE  `entity`.`status` = 'active'
      AND  (parent_offer_icon.id IS NOT NULL
              OR  icon.id IS NOT NULL ) 

我仍然愿意接受其他建议:)

让我们从把讨厌的
变成
联盟开始:

( SELECT  e.id AS eid,
          u.id AS uid,
          u.name AS uname
    FROM `uploads` AS u 
    INNER JOIN  `entity` AS e
       ON  u.`uploadable_id` = e.`id`
    WHERE  u.`uploadable_type` = 'Entity'
      AND  u.`category` = 'Icon'
      AND  e.status = 'active'
) UNION DISTINCT
( SELECT  e.id AS eid,
          u.id AS uid,
          u.name AS uname
    FROM `uploads` AS u 
    INNER JOIN   `entity` AS e
       ON  u.`uploadable_id` = e.`parent_entity_for_icon` 
    WHERE  u.`uploadable_type` = 'Entity'
      AND  u.`category` = 'Icon'
      AND  e.status = 'active'
)
这将需要以下一些索引:

uploads:  INDEX(uploadable_type, category, uploadable_id, id, name)
entity:   INDEX(parent_entity_for_icon, status, id)
(我假设
实体
主键(id)
?请提供
SHOW CREATE TABLE
,这样我就不用猜了。)如果这么长的索引有问题,请告诉我;我可能会提供一个解决办法

通过将
转换为
联合体
,可以为每个零件使用不同的索引。使用
,优化器通常会下注并执行一些低效的操作

请验证上面的查询是否运行快速并产生合理的输出。然后

SELECT  e.`id`, e.`requirements`, e.`description`, e.`status`,
        ev.`length`, ev.`quality`,
        s.`name`,
        uid, uname
    FROM ( the-query-above ) AS i
    JOIN `entity` AS e  ON e.id = i.eid
    LEFT JOIN  `states` AS s  ON s.`id` = e.`state_id`
    INNER JOIN  `entity_videos` AS ev  ON ev.`entity_id` = i.eid
除了每个表上的
主键(id)
,您还需要

entity_videos:  INDEX(entity_id)  -- good, or
entity_videos:  INDEX(entity_id, length, quality)  -- better ("covering")
不要使用
强制索引


有关索引创建的更多信息:

问题可能出在
条件下。尝试在(entity.id,entity.parent\u entity\u图标)中使用
可上载的\u id
@Barmar感谢您的建议,但它也不起作用。我忘了,几天前,当DB optimizer select中的记录少得多时,也许现在进行完全扫描比使用索引快得多?通常,当表变大时,索引更有用。但也许这个指数的基数太低了。使用
显示上传的索引
查看。尝试拆分为两个查询并与
UNION
组合。请阅读(搜索“为每个记录检查的范围”)。如果我理解正确,这并不意味着没有使用索引,而是在运行时(“为每个记录”)选择索引。但我不确定:-)感谢您的建议,我相信这可能是最好的,但在我的情况下,使用您和我的解决方案执行查询需要相当长的时间,但您的解决方案更难使用ORM实现。我看到了你的个人资料,看起来你是MySQL的专家:)。也许您会有兴趣看到完整的查询和表结构,我们可以私下继续对话(可能通过电子邮件或其他方式)?无论如何,谢谢你!!!是的,ORM往往会妨碍性能。rjweb.org上的mysql。您可以先用建议的索引对
联合
和等效的
进行计时。