我有一个拥有超过100,000条记录的数据库。我试图让所有订购的客户只能按客户的电子邮件字段(OrderEmail
)进行搜索。
SQL查询运行10分钟,然后超时。
如果我使用短日期范围,我可以获得结果,但仍需要3分钟。
如何优化语法以使其正常工作?
SELECT
tblOrders.OrderID,
tblOrders.OrderName,
tblOrders.OrderEmail,
tblOrders.OrderPhone,
tblOrders.OrderCountry,
tblOrders.OrderDate
FROM
tblOrders
LEFT JOIN tblOrders AS orders_join ON orders_join.OrderEmail = tblOrders.OrderEmail
AND NOT orders_join.OrderID = tblOrders.OrderID
WHERE
orders_join.OrderID IS NULL
AND (tblOrders.OrderDate BETWEEN '2015-01-01' AND '2017-03-01')
AND tblOrders.OrderDelivered = - 1
ORDER BY
tblOrders.OrderID ASC;
答案 0 :(得分:1)
我希望下面的内容能够正常运行 - 但我不能测试它,因为你没有提供样本数据。好吧,我添加了一个可用于查询的临时表定义....
但是,如果您实际上可以更改数据模型以使用INTEGER ID作为下订单的实体(而不是VARCHAR()电子邮件地址),那么您的速度会快得多。
===
正如你所看到的,它返回了Dent先生,Zaphod先生和Marvin先生,他们在示例数据中只出现过一次。
答案 1 :(得分:-1)
另一种可行的方法是,您可以按电子邮件地址分组,只获得一个条目。如果您希望获得多个订单的客户,它可能会出现不可预测的行为,但对于这种特殊情况应该没问题:
SELECT
tblOrders.OrderID,
tblOrders.OrderName,
tblOrders.OrderEmail,
tblOrders.OrderPhone,
tblOrders.OrderCountry,
tblOrders.OrderDate,
count(tblOrders.OrderID) as OrderCount
FROM
tblOrders
WHERE
tblOrders.OrderDate BETWEEN '2015-01-01' AND '2017-03-01'
AND tblOrders.OrderDelivered = - 1
GROUP BY
tblOrders.OrderEmail
HAVING
OrderCount = 1
ORDER BY
tblOrders.OrderID ASC;
另外,我怀疑如果你只用100k的记录看到如此长的查询时间,你可能在OrderEmail列上没有索引 - 我建议设置它,这可能有助于你的原始查询。
这在Oracle或SQL Server中不起作用,但它在MySQL和SQLite中有效。因此,虽然代码在不同的RDBMS之间不可移植,但它适用于此特定情况的 。