F# 查询表达式是不是具有与本机 SQL 相同的性能?

Posted

技术标签:

【中文标题】F# 查询表达式是不是具有与本机 SQL 相同的性能?【英文标题】:Do F# Query Expressions have same performance as Native SQL?F# 查询表达式是否具有与本机 SQL 相同的性能? 【发布时间】:2021-09-25 12:49:00 【问题描述】:

我注意到 F# 查询表达式示例看起来好像在进行计算之前获取了表的全部内容。这似乎比原生 SQL 效率低。或者性能应该是一样的。

// A query expression.
let query1 =
    query 
        for customer in db.Customers do
            select customer
    

【问题讨论】:

对应的SQL也会是SELECT * FROM customers,所以我看不出抓取整张表有什么区别...? 我只是从网上复制并粘贴了一个示例。但是假设我们有一个 1000 万条记录表,并且我们想要获取最近添加的条目。 F# 是否会检索 1000 万的整个列表,然后执行计算以获取最新条目?还是先在数据库中进行计算,然后将1条记录发送到f# 如果您在 F# 查询中仅获取 TOP 1 记录,那么通常应该转换为仅在 SQL 中获取 TOP 1 记录。这里的关键字是一般 - 这是它在大多数情况下应该工作的方式,但在某些情况下它的工作效果可能不如你希望的那样好。我认为在大多数情况下信任系统是合理的,但有一些诊断程序来仔细检查是很有用的。 【参考方案1】:

F# 查询表达式非常聪明。除了他们使用引号(类似于System.Linq.Expressions)将代码转换为SQL之外,我并不完全了解它们是如何工作的。 ORM 有 measurable overhead,原始查询会更快,但它们能够生成优化查询

鉴于这些模型和 ef-core 上下文

[<CLIMutable>] type Address =  Id: int; City: string; Country: string 
[<CLIMutable>] type Person =  Id: int; Name: string; Age: int; Address: Address 

type PeopleContext() =
    inherit DbContext()

    [<FSharp.Core.DefaultValue>]
    val mutable _people : DbSet<Person>

    member db.People
        with get () = db._people
        and set value = db._people <- value

    override _.OnConfiguring options =
        options.UseSqlite("Data source=db.db3") |> ignore

我已经创建了这个查询

query 
    for person in ctx.People do
        where (person.Age > 21)
        select person.Address.City
        take 1
 |> Seq.toArray |> printfn "%A"

翻译成这个sql

SELECT "a"."City"
FROM (
    SELECT "p"."AddressId"
    FROM "People" AS "p"
    WHERE "p"."Age" > 21
    LIMIT @__p_0
) AS "t"

【讨论】:

以上是关于F# 查询表达式是不是具有与本机 SQL 相同的性能?的主要内容,如果未能解决你的问题,请参考以下文章

SQL,查找两个给定名称在一列中是不是具有相同数字的查询

Hibernate + Java 性能较慢,但当我将 TOAD 与相同的本机 Oracle 查询一起使用时性能较快

如何通过 Spring Boot JPA 执行具有 INTERVAL 子句的本机 SQL 查询?

如何在 Spring Data JPA 中使用 CTE 表达式 WITH 子句

Mysql中查询一个表,把结果中的NULL替换成0,请写出sql语句

Microsoft SQL Server查询分析器不能与本机连接?