SQL 查询在 SQL Server CE 中很慢,但在 SQL Server 中很快

问题描述

我正在开发一个需要同时支持 SQL Server 和 SQL Server CE (4.0) 的产品。

我有两个表,其中一个是实体,另一个是关系表,如下所示:

客户
id
名称
订单
id
客户 ID
创建

我需要创建一个包含所有客户以及订单总数的列表。

由于 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 上的查询变得非常慢,即使使用“ FETCH NEXT 10 ROWS ONLY”仅获取 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],ordersCount.total as totalOrders
  FROM [customer] as c

在 SQL Server CE 上耗时 80 毫秒

但是当我使用 LEFT JOIN 执行整个查询时,查询需要超过 2 分钟(大约 14 000 名客户和 17-18 000 个订单。

执行计划表明“嵌套循环”占用了 100% 的时间用于 SQL Server CE 中的处理。但我似乎不明白为什么?

enter image description here

我有索引:

  • 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 毫秒内执行......这太奇怪了。

解决方法

首先,非常感谢@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 查询似乎是最好的选择。

感谢所有花时间帮助我的人!

,

拆分为两个查询,一个用于获取客户 ID,另一个用于获取相关订单,并确保两个查询都有良好的索引。

如果您要获取所有客户,请考虑获取所有订单的计数,以避免出现大的 IN 情况。

很高兴帮助您调查您是否私下共享数据库和查询。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...