SQL 查询在 SQL Server CE 中很慢,但在 SQL Server 中很快
Posted
技术标签:
【中文标题】SQL 查询在 SQL Server CE 中很慢,但在 SQL Server 中很快【英文标题】:SQL-query slow in SQL Server CE but fast in SQL Server 【发布时间】:2021-01-10 01:52:48 【问题描述】:我正在开发一个需要同时支持 SQL Server 和 SQL Server CE (4.0) 的产品。
我有两个表,一个是实体,另一个是关系表,如下所示:
Customer |
---|
id |
name |
Order |
---|
id |
customerId |
created |
我需要创建一个包含所有客户的列表以及订单总数。
由于 SQL Server CE 中存在限制,例如不能在选择语句中使用子查询,我想我可以这样查询:
SELECT [id]
,[name]
,ordersCount.total as totalOrders
FROM [customer] as c
LEFT JOIN(
SELECT customerId, Count(o.id) as total FROM orders AS o GROUP BY customerId
) as orderCount ON c.id = orderCount.customerId
ORDER BY id
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY
此查询在 SQL Server CE 和 SQL Server 中都有效,如果行数很少,它会非常快,但是当我们有很多或行时,查询在 SQL Server CE 上变得非常慢,即使使用 "仅获取下一个 10 行”以仅获取 10 行。我猜想即使我只获取 10 行,也会对所有行执行 LEFT-join。
执行查询的“部分”时间不到 100 毫秒,
SELECT customerId, Count(o.id) as total FROM orders AS o WHERE GROUP BY customerId
在 SQL Server CE 上需要 50 毫秒
SELECT [id]
,[name]
,ordersCount.total as totalOrders
FROM [customer] as c
在 SQL Server CE 上需要 80 毫秒
但是当我使用 LEFT JOIN 执行整个查询时,查询需要 2 分钟以上(大约 14 000 名客户有 17-18 000 个订单。
执行计划表明“嵌套循环”占用了 100% 的时间用于 SQL Server CE 中的处理。但我似乎无法弄清楚为什么?
我有以下索引:
customer.id(PK。包括:customer.id) order.customerId(包括 order.customerId)我想知道是否有某种方法可以使 SQL Server CE 上的查询更快?另外,我可以用另一种方式查询并获得相同的结果但更高效吗?
编辑: 我尝试将查询分为两个查询,首先获取即将显示的 50 个客户,然后查询计数。
SELECT [id]
,[name]
FROM [customer] as c
ORDER BY id
OFFSET 0 ROWS
FETCH NEXT 50 ROWS ONLY
然后从这 50 个中取出 id 并查询计数:
SELECT customerId, Count(o.id) as total
FROM orders AS o
WHERE customerID IN ([ids from query above])
GROUP BY customerId
这在大约 200 毫秒内执行......这太奇怪了。
【问题讨论】:
请在您的帖子中编辑您的索引是什么,并通过PasteThePlan.com分享查询计划 @Charlieface 我已经包含了索引(custom.id 和 order.customerId),试图将计划粘贴到您提供的链接中,但它说计划是无效的 XML,但我可以在 SSMS 中打开它。 完整的索引定义,带有INCLUDE
s。您是否在复制所有 XML,您可能错过了一个标签?还有 SQL Server 上的查询计划,以便我们进行比较。猜测一下,如果没有看到完整的计划,合并连接会更好,但由于某种原因没有选择
您的文字有误或已删除。 WHERE GROUP BY
是什么意思
我只是尝试将“LEFT JOIN”切换为“INNER JOIN”,它在不到 100 毫秒内执行。但有时客户可以在没有订单的情况下存在。感觉好奇怪,左连接和内连接能有这么大的区别?我已经更新到完整的索引描述。
【参考方案1】:
首先,非常感谢@ErikEJ,他非常好心地私下帮助了我。真是个好人,乐于助人!
ErikEJ 指出了我不知道的一件事,即 SQLCE 每个表和问题只使用一个索引,这可能对将来很有帮助。
在摆弄并阅读了这篇文章之后,我想出了尝试“CROSS APPLY”查询的想法。
类似这样的:
SELECT [id]
,[name]
,ot.total as totalOrders
FROM [customer] as c
CROSS APPLY (SELECT Count(o.id) as total FROM orders AS o WHERE o.customerId = c.id) as ot
ORDER BY id
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
此查询在 SQL Server 上执行大约 1 毫秒,在 SQLCE 上大约 300 毫秒。在性能方面,在这种情况下,获取前 50 行并基于它们使用组查询获取 COUNT() 仍然快 225% 左右。但是,如果需要对计数(哪个 id 需要)进行排序,CROSS APPLY-query 似乎是最好的选择。
感谢所有花时间帮助我的人!
【讨论】:
【参考方案2】:分成两个查询,一个用于获取客户 ID,另一个用于获取相关订单并确保两个查询都有良好的索引。
如果您要获取所有客户,请考虑获取所有订单的计数,以避免出现较大的 IN 条件。
很高兴帮助您调查您是否私下共享数据库和查询。
【讨论】:
“获取 50 个 id”解决方案非常适合这个用例,因为它不是基于计数的排序,但如果是这样的话,我仍然需要在查询中进行排序.我可以以某种方式私下分享 SQLCE 文件和查询,不想在这里全部发布 - 我应该离开 twitter 还是你更喜欢什么? 发邮件给我,地址在 Github 在您的 github 页面上找不到您的电子邮件,在您的博客上也没有,而且您在 Twitter 上禁用了 PM...=/ 哦,设法在你的旧博客上找到一些东西 =D 希望这个是正确的:ej*****@hotmail.com,我已经给你发了一封电子邮件。以上是关于SQL 查询在 SQL Server CE 中很慢,但在 SQL Server 中很快的主要内容,如果未能解决你的问题,请参考以下文章
简单查询在 laravel 中很慢(带有分页)但在 phpmyadmin 中非常快