【发布时间】:2022-01-20 10:29:49
【问题描述】:
我有三个表 (MariaDB 10.6.5):person、private_person 和 corporate_person。在 person 中存储了 Id,在其他表中存储了名称,它们都连接到每个 FK 的 person:
CREATE TABLE `person` (
`Id` INT(11) NOT NULL AUTO_INCREMENT,
`TypeOfPerson` ENUM('PRIVATE','CORPORATE') NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB;
CREATE TABLE `private_person` (
`PersonId` INT(11) NOT NULL,
`FirstName` VARCHAR(255) NULL DEFAULT NULL,
`LastName` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`PersonId`),
INDEX `IX_private_person_FirstName` (`FirstName`),
INDEX `IX_private_person_LastName` (`LastName`),
CONSTRAINT `FK_private_person_person_PersonId` FOREIGN KEY (`PersonId`) REFERENCES `person` (`Id`) ON UPDATE RESTRICT ON DELETE RESTRICT
) ENGINE=InnoDB;
CREATE TABLE `corporate_person` (
`PersonId` INT(11) NOT NULL,
`Name` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`PersonId`),
INDEX `IX_corporate_person_Name` (`Name`),
CONSTRAINT `FK_corporate_person_person_PersonId` FOREIGN KEY (`PersonId`) REFERENCES `person` (`Id`) ON UPDATE RESTRICT ON DELETE RESTRICT
) ENGINE=InnoDB;
现在我必须在 private_person 和 corporate_person 两个表中搜索名称:
SELECT `p`.Id
FROM `test`.`person` AS `p`
LEFT JOIN `test`.`private_person` AS `p0` ON `p`.`Id` = `p0`.`PersonId`
LEFT JOIN `test`.`corporate_person` AS `c0` ON `p`.`Id` = `c0`.`PersonId`
WHERE `p0`.`FirstName` = 'Test' OR p0.LastName = 'Test' OR `c0`.`Name` = 'Test';
所以我改变了查询:
SELECT Id FROM `test`.`person` WHERE Id IN (
SELECT p.Id
FROM `test`.`person` AS `p`
INNER JOIN `test`.`private_person` AS `p0` ON `p`.`Id` = `p0`.`PersonId`
WHERE `p0`.`FirstName` = 'Test' OR `p0`.`LastName` = 'Test'
UNION SELECT p.Id
FROM `test`.`person` AS `p`
INNER JOIN `test`.`corporate_person` AS `c0` ON `p`.`Id` = `c0`.`PersonId`
WHERE `c0`.`Name` = 'Test' ORDER BY Id);
我不明白为什么。内部查询只给出一定数量的 Id,为什么优化器不对这些简单数量的 Id 使用主索引?当我给出 Id 而不是内部查询时
SELECT Id FROM `test`.`person` WHERE Id IN (25251, 47413, 99851 ...);
即使我强制使用主索引 (SELECT Id FROM test.person FORCE INDEX (PRIMARY) WHERE ...),它也不会改变任何东西;根据查询优化器,现在使用主索引,但语句并不快:
如果优化器仅从子查询中获取一定数量的 Id,为什么不以更快(更)的方式使用主索引?
编辑:
很抱歉造成一些误解。我不想让查询更快,实际上我之前有一个解决我的具体问题的解决方案(比这里描述的更复杂的场景中的慢查询),也许我错过了更明确地写这个。但是在开发一个语句的过程中我尝试使用我对mysql和优化器的知识,在这里我很惊讶,我不明白,问题出在mariadb上。同样,OUTER 语句只获取一组 id,并且不能以正确的方式使用 PK。在SELECT Id FROM tabA WHERE Id IN (123, 456, 789) 中使用了PK 并且查询非常快,但是SELECT Id FROM tabA WHERE Id IN (SELECT Id FROM tabB WHERE ...) 没有以正确的方式使用PK,优化器会爬取整个表tabA。为什么?这就是我想问的问题。
【问题讨论】:
-
既然“人”都有“名字”,把
name移到公用表! -
这不是我的桌子,我不能改变结构。
标签: mysql indexing mariadb subquery query-optimization