我正在尝试为简单查询添加索引,但是添加索引会更改结果。索引是否可能影响查询结果?
当我删除索引时,结果返回到以前的状态。
查询是如此简单:
SELECT `gid`.`num_version_contrat` AS `num_version_contrat`, MAX(`gid`.`date_quittancement_echeance`) AS `max_date_quittancement_echeance`,`gid`.`montant_ht_actualise_echeance` AS `dernier_montant`
FROM `gid`
WHERE `gid`.num_version_contrat = "100313 V.0"
GROUP BY `gid`.`num_version_contrat`
ORDER BY `gid`.`num_version_contrat`
没有索引的结果是:
“ num_version_contrat”,“ max_date_quittancement_echeance”,“ dernier_montant”:
“ 100313 V.0”,“ 2018-04-01”,“ 32744”
添加索引:
CREATE INDEX `gid_idx_group_by_index` ON `gid` (`num_version_contrat`, `date_quittancement_echeance`, `montant_ht_actualise_echeance`)
具有索引的结果:
“ num_version_contrat”,“ max_date_quittancement_echeance”,“ dernier_montant”:
“ 100313 V.0”,“ 2018-04-01”,“ 2067.64”
您了解为什么两种情况下的结果都不同吗?
答案 0 :(得分:5)
您在select子句中有一个不在以下项分组的字段:gid
。montant_ht_actualise_echeance
这是MySQL和MariaDB的非常危险的功能,可能会导致意外的结果。
其他数据库将拒绝您的查询,但是除非您的SQL模式包含“ ONLY_FULL_GROUP_BY”,MariaDB会接受该查询,然后为您提供读取时遇到的第一个值。
添加索引会更改检索订单记录的方式,因此您会有所不同。实际上,即使添加/更新/删除其他记录也可能会更改组的结果,因为它可能会更改记录所在的块。
您可以通过将gid
。montant_ht_actualise_echeance
添加到Group by语句来修正查询。
或者,您可以选择一个聚集函数来计算总和,最大值,first_value或last_value。
回复评论:
GROUP BY的意思是“对于这些字段的每一个组合,都做一个记录”。因此,如果您具有“按年,月分组”,则您将在表中找到每年和每月组合的一条记录。 此外,将所有您知道在组中具有唯一值的值都放在此处。这意味着“季度”应该放在这里,因为一个月始终具有唯一的季度价值。如果所有记录的值都只有一个,则“公司名称”也应该放在此处。
对于所有其他字段,您需要告诉数据库如何处理找到的多个值。数字字段很简单:您可以求和(价格)或COUNT(id)等。对于文本字段,您需要选择:MIN,MAX(按字母顺序排列),FIRST_VALUE(即现在隐含的值)或什至GROUP_CONCAT将所有值附加到一个字符串中。
要获取与最后{max)gid
。date_quittancement_echeance
关联的gid.montant_ht_actualise_echeance的值,您需要首先标识具有最大日期的记录,并使用这些记录来选择所需的值从桌子上。
在MySQL / MariaDB中,通常是通过自联接表来完成的。如果表中的键/ ID列不明确,请使用该列进行联接,但如果没有,则将是这样:
SELECT `gid`.`num_version_contrat` AS `num_version_contrat`,
`gid`.`date_quittancement_echeance` AS `max_date_quittancement_echeance`,
`gid`.`montant_ht_actualise_echeance` AS `dernier_montant`
FROM `gid`
INNER JOIN
(
SELECT `gid`.`num_version_contrat` AS `num_version_contrat`,
MAX(`gid`.`date_quittancement_echeance`) AS max_date
FROM `gid`
GROUP BY `gid`.`num_version_contrat`
) last_dates
ON `gid`.`num_version_contrat` = `last_dates`.`num_version_contrat`
AND `gid`.`date_quittancement_echeance` = `last_dates`.`max_date`
WHERE `gid`.num_version_contrat = "100313 V.0"
ORDER BY `gid`.`num_version_contrat`
第一部分选择所需的字段。第二部分仅查找每个合同版本的max_dates,而INNER JOIN仅保留两个合同中找到的记录,并删除所有没有max_date的记录。
这假定WHERE子句仅用于测试,以后将被删除。 否则,整个分组依据就没有意义。