如何优化我的 mysql 查询以更快地检索数据
How to optimize my mysql query to retrieve data faster
我有一个独立的 table,我们通过每周作业插入它的数据,并在我们的搜索模块中检索数据。
当我执行以下 select 查询时,table 有大约 400 万条记录(并且会变得更大),它需要很长时间(大约 15 秒)。我正在使用 MySql 数据库。
SELECT
v.venueId,
(SELECT
MIN(totalPerPerson)
FROM
PricingArtifact pa
WHERE
pa.venueId = v.venueId
AND pa.mealId IN (SELECT
m.mealId
FROM
Meal m,
MealDay md
WHERE
m.mealId = md.mealId
AND m.mealDeletedAt IS NULL
AND md.mealDayDeletedAt IS NULL
AND m.venueId = v.venueId)) AS minPrice
FROM
Venue v
请注意
- 场地table只有12条记录。
- 我在 pricingArtifact 中有 venueId、totalPerPerson 的索引 table。
- 我试过连接而不是子查询,它给出了相同的结果。
- 用餐和用餐日table他们每个记录不到100条。
如果您只查找场地和每人的最低总数,您可以直接从 pricingArtifact 向下执行此操作,而无需实际场地,因为 pricingArtifact 具有 venueID...除非您也需要场地描述数据。
通过传递 属性,如果 V.VenueID = PA.VenueID,则 PA.VenueID 可以连接到 M.VenueID 而无需使用地点table。同样,PA.MealID 可以直接加入 meal 和 MealDay tables。
现在,您还提到了 400 万条记录的 table。您的相关查询(查询 min() 值 perPerson/perVenue 非常昂贵,因为您已经遇到过,因为它对第一个 table 中的每条记录进行子查询。您真的需要回顾所有历史记录吗记录,或者是否有一些 DATE 字段,比如你只关心最近的 activity...比如说 30 天?一旦数据完成,它真的会改变吗?也许保留一个摘要 table 作为分析定价率的基础。
现在,对于索引。我会提出以下建议。
table index
PricingArtifact (venueID, mealID, totalPerPerson )
Meal (mealID, MealDeletedAt )
MealDay (mealID, MealDayDeletedAt )
SELECT
PA.venueID
MIN( PA.TotalPerPerson ) as VenueMinPerPerson
from
PricingArtifact PA
JOIN meal M
ON PA.MealID = M.MealID
AND M.MealDeletedAt IS NULL
JOIN MealDay MD
ON PA.MealID = MD.MealID
AND MD.MealDayDeletedAt Is NULL
我想你根本不需要连接到 venue
,如果真的只有 12 个的话。
SELECT pa.venueID, MIN(PA.TotalPerPerson) as minPrice
FROM PricingArtifact pa
WHERE EXISTS (SELECT 1
FROM Meal m JOIN
MealDay md
ON m.mealId = md.mealId
WHERE m.mealDeletedAt IS NULL AND
md.mealDayDeletedAt IS NULL AND
pa.mealId = m.mealId
)
GROUP BY pa.venueId;
对于此查询,您需要在 Meal(mealId, mealDeletedAt)
和 MealDay(mealId, mealDayDeletedAt)
上建立索引。
对您的查询有些好奇:
- 我通常不会将表达式
MIN(totalPerPerson)
描述为 "MinTotalPrice"。
Meal
、MailDay
和 PriceArtifact
上的联接都在同一列上。好像很奇怪。
我有一个独立的 table,我们通过每周作业插入它的数据,并在我们的搜索模块中检索数据。
当我执行以下 select 查询时,table 有大约 400 万条记录(并且会变得更大),它需要很长时间(大约 15 秒)。我正在使用 MySql 数据库。
SELECT
v.venueId,
(SELECT
MIN(totalPerPerson)
FROM
PricingArtifact pa
WHERE
pa.venueId = v.venueId
AND pa.mealId IN (SELECT
m.mealId
FROM
Meal m,
MealDay md
WHERE
m.mealId = md.mealId
AND m.mealDeletedAt IS NULL
AND md.mealDayDeletedAt IS NULL
AND m.venueId = v.venueId)) AS minPrice
FROM
Venue v
请注意
- 场地table只有12条记录。
- 我在 pricingArtifact 中有 venueId、totalPerPerson 的索引 table。
- 我试过连接而不是子查询,它给出了相同的结果。
- 用餐和用餐日table他们每个记录不到100条。
如果您只查找场地和每人的最低总数,您可以直接从 pricingArtifact 向下执行此操作,而无需实际场地,因为 pricingArtifact 具有 venueID...除非您也需要场地描述数据。
通过传递 属性,如果 V.VenueID = PA.VenueID,则 PA.VenueID 可以连接到 M.VenueID 而无需使用地点table。同样,PA.MealID 可以直接加入 meal 和 MealDay tables。
现在,您还提到了 400 万条记录的 table。您的相关查询(查询 min() 值 perPerson/perVenue 非常昂贵,因为您已经遇到过,因为它对第一个 table 中的每条记录进行子查询。您真的需要回顾所有历史记录吗记录,或者是否有一些 DATE 字段,比如你只关心最近的 activity...比如说 30 天?一旦数据完成,它真的会改变吗?也许保留一个摘要 table 作为分析定价率的基础。
现在,对于索引。我会提出以下建议。
table index
PricingArtifact (venueID, mealID, totalPerPerson )
Meal (mealID, MealDeletedAt )
MealDay (mealID, MealDayDeletedAt )
SELECT
PA.venueID
MIN( PA.TotalPerPerson ) as VenueMinPerPerson
from
PricingArtifact PA
JOIN meal M
ON PA.MealID = M.MealID
AND M.MealDeletedAt IS NULL
JOIN MealDay MD
ON PA.MealID = MD.MealID
AND MD.MealDayDeletedAt Is NULL
我想你根本不需要连接到 venue
,如果真的只有 12 个的话。
SELECT pa.venueID, MIN(PA.TotalPerPerson) as minPrice
FROM PricingArtifact pa
WHERE EXISTS (SELECT 1
FROM Meal m JOIN
MealDay md
ON m.mealId = md.mealId
WHERE m.mealDeletedAt IS NULL AND
md.mealDayDeletedAt IS NULL AND
pa.mealId = m.mealId
)
GROUP BY pa.venueId;
对于此查询,您需要在 Meal(mealId, mealDeletedAt)
和 MealDay(mealId, mealDayDeletedAt)
上建立索引。
对您的查询有些好奇:
- 我通常不会将表达式
MIN(totalPerPerson)
描述为 "MinTotalPrice"。 Meal
、MailDay
和PriceArtifact
上的联接都在同一列上。好像很奇怪。