为什么Swift编译时间这么慢?

时间:2014-08-27 21:57:05

标签: compilation swift

我正在使用Xcode 6 Beta 6。

这是一段时间以来一直困扰着我的事情,但它现在已经达到了几乎无法使用的程度。

我的项目开始有一个体面的大小的65个Swift文件和一些桥接的Objective-C文件(这实际上不是问题的原因)。

似乎对任何Swift文件稍作修改(比如在应用程序中几乎不使用的类中添加一个简单的空格)将导致重新编译指定目标的整个Swift文件。

经过深入调查后,我发现占用编译时间差不多100%的是CompileSwift阶段,Xcode在你的所有Swift文件上运行swiftc命令目标

我做了一些进一步的调查,如果我只保留app委托与默认控制器,编译速度非常快,但随着我添加越来越多的项目文件,编译时间开始变得非常慢。

现在只有65个源文件,每次编译大约需要8/10秒。根本不是 swift

除了this one之外,我还没有看到任何关于此问题的帖子,但它是Xcode 6的旧版本。所以我想知道我是否是唯一一个那种情况。

更新

我在GitHubAlamofireEulerCryptoSwift等{{}}检查了一些Swift项目,但没有一个项目有足够的Swift文件进行实际比较。我找到的唯一一个开始体面大小的项目是SwiftHN,即使它只有十几个源文件,我仍然可以验证相同的东西,一个简单的空间和整个项目需要重新编译,这需要花费一点时间(2/3秒)。

与Objective-C代码相比,分析器和编译都非常快,这真的感觉Swift永远无法处理大型项目,但请告诉我,我错了。

使用Xcode 6 Beta 7进行更新

仍然没有任何进步。这开始变得荒谬了。由于Swift中缺少#import,我真的不知道Apple将如何优化它。

使用Xcode 6.3和Swift 1.2更新

Apple已添加incremental builds(以及许多其他编译器优化)。您必须将代码迁移到Swift 1.2以查看这些优势,但Apple在Xcode 6.3中添加了一个工具来帮助您这样做:

Enter image description here

无论其

不要像我一样快乐。他们用来制作构建增量的图解算器还没有很好地优化。

首先,它不会查看函数签名更改,因此如果在一个方法的块中添加空格,则将重新编译依赖于该类的所有文件。

其次,它似乎是根据重新编译的文件创建树,即使更改不会影响它们。例如,如果将这三个类移动到不同的文件中

class FileA: NSObject {
    var foo:String?
}
class FileB: NSObject {
    var bar:FileA?
}
class FileC: NSObject {
    var baz:FileB?
}

现在,如果修改FileA,编译器显然会将FileA标记为要重新编译。它还会重新编译FileB(基于对FileA的更改可以正常),FileC,因为FileB已重新编译,并且这非常糟糕,因为FileC从未使用FileA

所以我希望他们改进依赖树求解器...我已经使用此示例代码打开了radar

使用Xcode 7 beta 5和Swift 2.0更新

昨天Apple发布了beta 5,在发行说明中我们可以看到:

  

Swift Language&编译器   •增量构建:仅更改函数体不应再导致重建依赖文件。 (15352929)

我试了一下,我必须说它现在真的很好(真的!)。他们极大地优化了swift中的增量构建。

我强烈建议您使用XCode 7 beta 5创建一个swift2.0分支并使代码保持最新。您会对编译器的增强感到高兴(不过我要说的是全局状态XCode 7仍然很慢而且有问题

使用Xcode 8.2更新

自从我上次更新此问题以来已经有一段时间了,所以现在就是这样。

我们的应用程序现在大约有20k行几乎完全是Swift代码,这是不错的但不是很出色。它经历了迅速的2而不是迅速的3迁移。在2014年中期的Macbook pro(2.5 GHz Intel Core i7)上编译需要大约5 / 6m,这在干净的构建上是可以的。

然而,尽管Apple声称:

,增量构建仍然是一个笑话
  

当只发生很小的变化时,Xcode不会重建整个目标。 (28892475)

显然我觉得我们很多人在看完这个废话后笑了起来(给我项目的任何文件添加一个私有(私有!)属性都会重新编译整个东西......)

我想在Apple开发人员论坛上向大家指出this thread,这些论坛上有关于该问题的更多信息(以及有兴趣的Apple开发者之间的沟通)

基本上人们已经提出了一些尝试来改进增量构建的东西:

  1. HEADER_MAP_USES_VFS项目设置添加到true
  2. 从您的计划中停用Find implicit dependencies
  3. 创建一个新项目并将文件层次结构移动到新项目。
  4. 我会尝试解决方案3,但解决方案1/2并不适合我们。

    在这整个情况下,具有讽刺意味的是,看看这个问题的第一篇文章,我们使用的是Xcode 6,我相信swift 1或swift 1.1代码,当我们达到第一次编译时的缓慢,现在大约两年尽管Apple实际上有所改进,但情况与Xcode 6一样糟糕。具有讽刺意味。

    我实际上真的后悔为我们的项目选择Swift over Obj / C,因为它涉及到日常的挫败感。 (我甚至切换到AppCode,但这是另一个故事)

    无论如何我看到这篇文章在撰写本文时有32k +次观看次数和143次以上,所以我想我不是唯一一个。虽然对这种情况持悲观态度,但在隧道尽头可能还会有一些亮点。

    如果你有时间(和勇气!)我猜Apple会对此表示欢迎。

    下次再来!干杯

    使用Xcode 9更新

    今天偶然发现this。 Xcode悄然引入了一个新的构建系统,以改善当前可怕的性能。您必须通过工作区设置启用它。

    enter image description here

    已尝试过,但会在完成后更新此帖子。看起来很有希望。

22 个答案:

答案 0 :(得分:66)

嗯,事实证明Rob Napier是对的。

是一个单个文件(实际上是一个方法)导致编译器进入berzek。

现在不要误会我的意思。 Swift每次都会重新编译你的所有文件,但现在最棒的是,Apple在其编译的文件上添加了实时编译反馈,因此Xcode 6 GM现在可以显示正在编译的Swift文件以及实时编译的状态正如您在此屏幕截图中看到的那样:

Enter image description here

因此,知道哪些文件花了这么长时间,这非常方便。就我而言,这是一段代码:

var dic = super.json().mutableCopy() as NSMutableDictionary
dic.addEntriesFromDictionary([
        "url" : self.url?.absoluteString ?? "",
        "title" : self.title ?? ""
        ])

return dic.copy() as NSDictionary

因为属性title的类型为var title:String?而非NSString。将它添加到NSMutableDictionary时,编译器会发疯。

将其更改为:

var dic = super.json().mutableCopy() as NSMutableDictionary
dic.addEntriesFromDictionary([
        "url" : self.url?.absoluteString ?? "",
        "title" : NSString(string: self.title ?? "")
        ])

return dic.copy() as NSDictionary

使编辑从10/15秒(甚至更多)下降到一秒......太棒了。

答案 1 :(得分:39)

我们已经尝试了很多东西来解决这个问题,因为我们有大约10万行Swift代码和300k行ObjC代码。

我们的第一步是根据函数编译时输出优化所有函数(例如,如此处所述https://thatthinginswift.com/debug-long-compile-times-swift/

接下来我们编写了一个脚本,将所有swift文件合并到一个文件中,这打破了访问级别,但它将编译时间从5-6分钟带到了~1分钟。

现在已经不存在了,因为我们向Apple询问了这个问题,他们建议我们应该做以下事情:

  1. 在“Swift编译器 - 代码生成”构建设置中启用“整个模块优化”。选择'Fast, Whole Module Optimization'
  2. enter image description here

    1. 在“Swift编译器 - 自定义标志”中,为您的开发版本添加'-Onone'
    2. enter image description here enter image description here

      设置这些标志后,编译器将一步编译所有Swift文件。我们发现使用我们的合并脚本,这比单独编译文件要快得多。但是,如果没有'-Onone'覆盖,它也会优化整个模块,这会更慢。当我们在其他Swift标志中设置'-Onone'标志时,它会停止优化,但它不会停止一步编译所有Swift文件。

      有关整个模块优化的更多信息,请查看Apple的博客文章 - https://swift.org/blog/whole-module-optimizations/

      我们发现这些设置允许我们的Swift代码在30秒内编译:-)我没有证据表明它如何在其他项目上运行,但我建议如果Swift编译时间仍然是一个问题,请尝试一下对你而言。

      请注意,对于App Store版本,您应该保留'-Onone'标记,因为建议对生产版本进行优化。

答案 2 :(得分:33)

如果您正在尝试识别减慢编译时间的特定文件,可以尝试通过xctool从命令行编译它,这将为您提供逐个文件的编译时间。

需要注意的是,默认情况下,它会为每个CPU核心同时构建2个文件,并且不会为您提供“净”经过时间,而是绝对“用户”时间。这样,所有时间都在并行化文件之间进行,看起来非常相似。

为了解决这个问题,-jobs标志设置为1 ,以便它不会并行化文件构建。这将需要更长的时间,但最终你将有“净”编译时间,你可以逐个文件进行比较。

这是一个应该起作用的示例命令:

xctool -workspace <your_workspace> -scheme <your_scheme> -jobs 1 build

“编译Swift文件”阶段的输出类似于:

...
   ✓ Compile EntityObserver.swift (1623 ms)
   ✓ Compile Session.swift (1526 ms)
   ✓ Compile SearchComposer.swift (1556 ms)
...

通过此输出,您可以快速识别哪些文件比其他文件花费的时间更长。此外,您可以高精度地确定您的重构(显式强制转换,类型提示等)是否正在降低特定文件的编译时间。

注意:从技术上讲,您也可以使用xcodebuild进行操作,但输出非常冗长且难以使用。

答案 3 :(得分:30)

这可能与项目的大小无关。它可能是一些特定的代码,甚至可能只有一行。您可以通过尝试一次编译一个文件而不是整个项目来测试它。或者尝试观看构建日志,看看哪个文件花了这么长时间。

作为可能导致问题的代码类型的示例,this 38-line gist需要花费一分多钟才能在beta7中进行编译。所有这一切都是由这一块引起的:

let pipeResult =
seq |> filter~~ { $0 % 2 == 0 }
  |> sorted~~ { $1 < $0 }
  |> map~~ { $0.description }
  |> joinedWithCommas

通过一两行简化它几乎立即编译。问题在于这会导致编译器中的指数增长(可能是因子增长)。显然这并不理想,如果你可以隔离这种情况,你应该打开雷达来帮助解决这些问题。

答案 4 :(得分:25)

就我而言,Xcode 7没有任何区别。我有多个函数需要几秒钟才能编译。

示例

// Build time: 5238.3ms
return CGSize(width: size.width + (rightView?.bounds.width ?? 0) + (leftView?.bounds.width ?? 0) + 22, height: bounds.height)

打开选项后,构建时间下降 99.4%

// Build time: 32.4ms
var padding: CGFloat = 22
if let rightView = rightView {
    padding += rightView.bounds.width
}

if let leftView = leftView {
    padding += leftView.bounds.width
}
return CGSizeMake(size.width + padding, bounds.height)

查看this postthis post中的更多示例。

为Xcode构建时间分析器

I developed an Xcode plug-in对于遇到这些问题的人来说可能会派上用场。

image

Swift 3似乎有所改进,所以希望我们能够更快地看到我们的Swift代码编译。

答案 5 :(得分:16)

解决方案是铸造。

我有大量的词典,如下:

["title" : "someTitle", "textFile" : "someTextFile"],
["title" : "someTitle", "textFile" : "someTextFile"],
["title" : "someTitle", "textFile" : "someTextFile"],
["title" : "someTitle", "textFile" : "someTextFile"],
.....

编译它大约需要40分钟。直到我输出这样的词典:

["title" : "someTitle", "textFile" : "someTextFile"] as [String : String],
["title" : "someTitle", "textFile" : "someTextFile"] as [String : String],
["title" : "someTitle", "textFile" : "someTextFile"] as [String : String],
....

这适用于我遇到的关于我硬编码到我的应用程序中的数据类型的几乎所有其他问题。

答案 6 :(得分:16)

可能我们无法修复Swift编译器,但我们可以修复的是我们的代码!

Swift编译器中有一个隐藏选项,它打印出编译器编译每个函数所需的确切时间间隔:-Xfrontend -debug-time-function-bodies。它允许我们在代码中找到瓶颈并显着缩短编译时间。

在终端中简单运行以下内容并分析结果:

xcodebuild -workspace App.xcworkspace -scheme App clean build OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" | grep [1-9].[0-9]ms | sort -nr > culprits.txt

很棒的Brian Irace写了一篇关于它的精彩文章Profiling your Swift compilation times

答案 7 :(得分:15)

需要注意的一点是,嵌套类型的Swift类型推理引擎可能会非常慢。通过观察需要很长时间然后复制的单个编译单元的构建日志,您可以大致了解造成缓慢的原因。将完整的Xcode-spawned命令粘贴到终端窗口,然后按CTRL-来获取一些诊断信息。请查看http://blog.impathic.com/post/99647568844/debugging-slow-swift-compile-times以获取完整示例。

答案 8 :(得分:9)

还要确保在编译调试时(Swift或Objective-C),设置为仅构建活动架构:

enter image description here

答案 9 :(得分:6)

由于所有这些东西都在Beta中,并且由于Swift编译器(至少截至今天)没有打开,我想你的问题没有真正的答案。

首先,将Objective-C与Swift编译器进行比较有点残酷。 Swift仍处于测试阶段,我相信Apple正致力于提供功能和修复错误,而不仅仅是提供闪电般的速度(你不会通过购买家具来开始建造房屋)。我想Apple会在适当的时候优化编译器。

如果由于某种原因必须完整编译所有源文件,则可以选择创建单独的模块/库。但是这个选项还不可能,因为Swift在语言稳定之前不能允许库。

我的猜测是他们会优化编译器。出于同样的原因,我们无法创建预编译的模块,很可能编译器需要从头开始编译所有内容。但是,一旦语言达到稳定版本和二进制文件&#39;格式不再改变,我们将能够创建我们的库,也许(?)编译器也将能够优化其工作。

只是猜测,因为只有Apple知道......

答案 10 :(得分:5)

对于Xcode 8,转到项目设置,然后转到编辑器&gt;添加构建设置&gt;添加用户定义的设置,并添加以下内容:

SWIFT_WHOLE_MODULE_OPTIMIZATION = YES

添加此标志会将我们的清理构建编译时间从7分钟下降到65秒,这对于40KLOC swift项目来说是奇迹般的。也可以确认2位朋友在企业项目上看到了类似的改进。

我只能假设这是Xcode 8.0中的某种错误

编辑:对于某些人来说,它似乎不再适用于Xcode 8.3。

答案 11 :(得分:4)

对于调试和测试,请确保使用以下设置将编译时间从大约20分钟缩短到不到2分钟,

  1. 在项目构建设置中,搜索“优化” 将调试变为“最快[-O3]”或更高。
  2. 为活动架构设置构建:是
  3. 调试信息格式:DWARF
  4. 整个模块优化:否
  5. 我浪费了无数个小时等待项目建设只是为了意识到我必须进行一点改变并且不得不等待另外30分钟来测试它。这些设置对我有用。 (我还在尝试设置)

    但是,请确保至少设置“DWARF with dSYM”(如果你想监视你的应用程序)和Build Active Architecture为“NO”以进行发布/存档以推送到iTunes Connect(我记得在这里浪费了几个小时)太)。

答案 12 :(得分:4)

编译器花费大量时间推断和检查类型。因此添加类型注释有助于编译器。

如果你有很多链式函数调用,比如

let sum = [1,2,3].map({String($0)}).flatMap({Float($0)}).reduce(0, combine: +)

然后编译器需要一段时间来确定sum的类型应该是什么。添加类型有帮助。还有助于将间歇性步骤拉入单独的变量中。

let numbers: [Int] = [1,2,3]
let strings: [String] = sum.map({String($0)})
let floats: [Float] = strings.flatMap({Float($0)})
let sum: Float = floats.reduce(0, combine: +)

特别是对于数字类型CGFloatInt,它可以提供很多帮助。像2这样的文字数字可以表示许多不同的数字类型。因此编译器需要从上下文中找出它是哪一个。

还应该避免花费大量时间查看+的函数。使用几个+连接几个数组很慢,因为编译器需要确定应为每个+调用+的哪个实现。因此,如果可能,请使用var a: [Foo]代替append()

您可以添加警告以检测which functions are slow to compile in Xcode

构建设置中,您的目标搜索其他Swift标志并添加

-Xfrontend -warn-long-function-bodies=100

警告每个编译时间超过100毫秒的函数。

答案 13 :(得分:4)

Swift数组和字典构造似乎是一个非常受欢迎的原因(特别适合那些来自Ruby背景的人),即

var a = ["a": "b",
         "c": "d",
         "e": "f",
         "g": "h",
         "i": "j",
         "k": "l",
         "m": "n",
         "o": "p",
         "q": "r",
         "s": "t",
         "u": "v",
         "x": "z"]

可能是应该解决它的原因:

var a = NSMutableDictionary()
a["a"] = "b"
a["c"] = "d"
... and so on

答案 14 :(得分:4)

不幸的是,Swift编译器仍然没有针对快速和增量编译进行优化(从Xcode 6.3 beta开始)。同时,您可以使用以下一些技术来改进Swift编译时间:

  • 将应用拆分为Frameworks以减少重新编译的影响。但请注意,您必须避免在应用中出现循环依赖关系。有关此主题的更多信息,请查看此帖子:http://bits.citrusbyte.com/improving-swift-compile-time/

  • 将Swift用于项目中非常稳定并且不经常更改的部分。对于需要经常更改的其他区域或需要完成大量编译/运行迭代的区域(几乎任何与UI相关的东西),最好使用混合匹配方法使用Objective-C。

    < / LI>
  • 尝试使用&#39;注入Xcode&#39;

  • 运行时代码注入
  • 使用roopc方法:http://roopc.net/posts/2014/speeding-up-swift-builds/

  • 通过提供一些带有显式强制转换的提示来缓解swift类型的推理引擎。

答案 15 :(得分:3)

重启我的Mac确实对此问题感到奇怪。我只需重新启动就可以从15分钟构建到30秒构建。

答案 16 :(得分:2)

对于混合使用Objective-C和Swift代码的项目,我们可以在-enable-bridging-pch中设置Other Swift Flags。有了这个,桥接头只被解析一次,结果(一个临时的“预编译头”或“PCH”文件)被缓存并在目标中的所有Swift文件中重用。 Apple声称它将构建时间缩短了30%。 Reference Link:

注意:这仅适用于Swift 3.1及更高版本。

答案 17 :(得分:1)

Swift编译时间was improved in new Xcode 6.3

  

编译器改进

     

Swift 1.2编译器的设计更加稳定并且有所改进   各方面的表现。这些变化也提供了更好的   在Xcode中使用Swift时的经验。一些最明显的   改进包括:

     

增量构建

     

将不再重新编译未更改的源文件   默认情况下,这将显着改善最常见的构建时间   案例。您的代码可能仍需要对代码进行更大的结构更改   要重建的多个文件。

     

更快的可执行文件

     

Debug构建产生运行速度相当快且新的二进制文件   优化可以提供更好的发布构建性能。

     

更好的编译器诊断

     

更清晰的错误和警告消息,以及新的Fix-it,制作它   更容易编写适当的Swift 1.2代码。

     

稳定性改进

     

最常见的编译器崩溃已得到修复。你也应该看到   Xcode编辑器中的SourceKit警告更少。

答案 18 :(得分:0)

这是另一个可能导致类型推断大幅减速的案例。 合并运算符

更改以下行:

abs(some_optional_variable ?? 0)

abs((some_optional_variable ?? 0) as VARIABLE_TYPE)

帮助我将编译时间从70s提高到13s

答案 19 :(得分:0)

在Xcode 6.3.1中没有什么对我有用 - 当我添加arround 100 Swift文件时,Xcode随机挂在构建和/或索引上。我尝试过模块化选项但没有成功。

安装和使用Xcode 6.4 Beta 实际上对我有用。

答案 20 :(得分:0)

这对我来说就像魔术一样 - Speed Up Swift Compilation。它将编译时间从10分钟缩短到3分钟。

它说你应该在 Whole Module Optimization 中添加 -Onone 时打开 Other Swift Flags

我在Swift 3 / Xcode 8.3 上使用 Xcode 8.2

答案 21 :(得分:0)

在一个表达式中

混合整数文字和浮点文字也会导致较长的编译时间。

SELECT
    d.ID_TEMP
    ,LEFT(d.tanggal, 4) AS year
    ,SUBSTRING(d.tanggal, 5, 2) AS bulan
    ,RIGHT(d.tanggal, 2) AS tanggal
    ,d.jenis_rekening
    ,d.status_penerima
    ,d.kategori_penerima
    ,d.status_pembayar
    ,d.kategori_pembayar
    ,d.hubungan_keuangan
    ,d.sandi_negara
    ,d.jenis_valuta
    ,d.nilai_transaksi
    ,d.in_out
    ,d.tujuan_transaksi
    ,d.kode_cabang
    ,flag_transaksi = CASE WHEN d.jenis_rekening = '3C'
            AND CAST(d.nilai_transaksi2 AS FLOAT) <= CAST('10000' AS FLOAT) THEN 'K' WHEN SUBSTRING(d.kode_swift_bank_pengirim, 5, 2) = 'ID'
            AND SUBSTRING(d.kode_swift_bank_penerima, 5, 2) = 'ID'
            AND d.in_out = '1' THEN 'K' WHEN d.jenis_rekening = '3C'
            AND CAST(d.nilai_transaksi2 AS FLOAT) > CAST('10000' AS FLOAT) THEN 'L' ELSE 'K' END
    ,d.nama_penerima
    ,d.jenis_no_identifikasi_penerima
    ,d.no_identifikasi_penerima
    ,d.nama_pembayar
    ,d.jenis_no_identifikasi_pembayar
    ,d.no_identifikasi_pembayar
    ,d.kode_swift_bank_pengirim
    ,d.kode_swift_bank_penerima
    ,d.detail_transaksi
    ,d.tujuan_transaksi_2015
    ,d.dokumen
    ,d.gol_debitur_penerima
    ,d.gol_debitur_pembayar
    ,d.dokumen_pendukung_lld1
    ,d.periode
    ,d.kurs_asli
    ,d.kurs_dollar
    ,d.flag_kurs
    ,d.flag_valid
    ,d.Jenis_Rekening_lld2
    ,d.Jenis_Valuta_lld2
    ,d.Sandi_Negara_lld2
    ,d.sandi_bank
    ,mp.IDPosisi
FROM
    (SELECT 
         c.ID_TEMP
        ,c.kode_cabang
        ,c.tanggal
        ,c.jenis_rekening
        ,c.status_penerima
        ,c.kategori_penerima
        ,c.status_pembayar
        ,c.kategori_pembayar
        ,c.hubungan_keuangan
        ,c.sandi_negara
        ,c.jenis_valuta
        ,c.nilai_transaksi
        ,c.in_out
        ,c.tujuan_transaksi
        ,c.tujuan_transaksi_2015
        ,c.nama_penerima
        ,c.jenis_no_identifikasi_penerima
        ,c.nama_pembayar
        ,c.jenis_no_identifikasi_pembayar
        ,c.kode_swift_bank_pengirim
        ,c.nomor_ft
        ,c.f_id
        ,c.negara_depository
        ,c.no_identifikasi_penerima
        ,c.jenis_identifikasi_pembayar
        ,c.no_identifikasi_pembayar
        ,c.kode_swift_bank_penerima
        ,c.detail_transaksi
        ,c.dokumen
        ,c.gol_debitur_penerima
        ,c.gol_debitur_pembayar
        ,c.dokumen_pendukung_lld1
        ,c.periode
        ,c.kurs_asli
        ,c.kurs_dollar
        ,c.flag_kurs
        ,c.flag_valid
        ,nilai_transaksi2 = CASE WHEN c.jenis_rekening = '3C'
                AND c.jenis_valuta <> 'USD'
                AND c.flag_kurs = '1' THEN ROUND(ROUND(CAST(c.nilai_transaksi AS FLOAT) * CAST(c.kurs_asli AS FLOAT), 2) / CAST(c.kurs_dollar AS FLOAT), 2) WHEN c.jenis_rekening = '3C'
                AND c.jenis_valuta <> 'USD'
                AND c.flag_kurs = '0' THEN '0' WHEN c.jenis_rekening = '3C'
                AND c.jenis_valuta = 'USD'
                AND c.flag_kurs = '0' THEN '0' WHEN c.jenis_rekening <> '3C'
                AND c.flag_kurs = '0' THEN '0' ELSE c.nilai_transaksi END
        ,c.flag_valid
        ,c.Jenis_Rekening_lld2
        ,c.Jenis_Valuta_lld2
        ,c.Sandi_Negara_lld2
        ,c.sandi_bank
    FROM (
        SELECT b.ID_TEMP
            ,b.kode_cabang
            ,b.tanggal
            ,b.jenis_rekening
            ,b.status_penerima
            ,b.kategori_penerima
            ,b.status_pembayar
            ,b.kategori_pembayar
            ,b.hubungan_keuangan
            ,b.sandi_negara
            ,b.jenis_valuta
            ,b.nilai_transaksi
            ,b.in_out
            ,b.tujuan_transaksi
            ,b.tujuan_transaksi_2015
            ,b.nama_penerima
            ,b.jenis_no_identifikasi_penerima
            ,b.nama_pembayar
            ,b.jenis_no_identifikasi_pembayar
            ,b.kode_swift_bank_pengirim
            ,b.nomor_ft
            ,b.f_id
            ,b.negara_depository
            ,b.no_identifikasi_penerima
            ,b.jenis_identifikasi_pembayar
            ,b.no_identifikasi_pembayar
            ,b.kode_swift_bank_penerima
            ,b.detail_transaksi
            ,b.dokumen
            ,b.gol_debitur_penerima
            ,b.gol_debitur_pembayar
            ,b.dokumen_pendukung_lld1
            ,b.periode
            ,b.kurs_asli
            ,b.kurs_dollar
            ,b.flag_valid
            ,flag_kurs = CASE WHEN b.kurs_asli <> '0'
                    AND b.kurs_dollar <> '0' THEN '1' ELSE '0' END
            ,b.Jenis_Rekening_lld2
            ,b.Jenis_Valuta_lld2
            ,b.Sandi_Negara_lld2
            ,b.sandi_bank
        FROM (
            SELECT a.ID_TEMP
                ,a.kode_cabang
                ,a.tanggal
                ,a.jenis_rekening
                ,a.status_penerima
                ,a.kategori_penerima
                ,a.status_pembayar
                ,a.kategori_pembayar
                ,a.hubungan_keuangan
                ,a.sandi_negara
                ,a.jenis_valuta
                ,a.nilai_transaksi
                ,a.in_out
                ,a.tujuan_transaksi
                ,a.tujuan_transaksi_2015
                ,a.nama_penerima
                ,a.jenis_no_identifikasi_penerima
                ,a.nama_pembayar
                ,a.jenis_no_identifikasi_pembayar
                ,a.kode_swift_bank_pengirim
                ,a.nomor_ft
                ,a.f_id
                ,a.negara_depository
                ,a.no_identifikasi_penerima
                ,a.jenis_identifikasi_pembayar
                ,a.no_identifikasi_pembayar
                ,a.kode_swift_bank_penerima
                ,a.detail_transaksi
                ,a.dokumen
                ,a.gol_debitur_penerima
                ,a.gol_debitur_pembayar
                ,a.dokumen_pendukung_lld1
                ,a.periode
                ,a.flag_valid
                ,a.Jenis_Rekening_lld2
                ,a.Jenis_Valuta_lld2
                ,a.Sandi_Negara_lld2
                ,a.sandi_bank
                ,ISNULL(mk.kurs, 0) AS kurs_asli
                ,ISNULL(mk2.kurs, 0) AS kurs_dollar
            FROM (
                SELECT ttt.ID_TEMP
                    ,ttt.kode_cabang
                    ,ttt.tanggal
                    ,ttt.jenis_rekening
                    ,ttt.status_penerima
                    ,ttt.kategori_penerima
                    ,ttt.status_pembayar
                    ,ttt.kategori_pembayar
                    ,ttt.hubungan_keuangan
                    ,ttt.sandi_negara
                    ,ttt.jenis_valuta
                    ,ttt.nilai_transaksi
                    ,ttt.in_out
                    ,ttt.tujuan_transaksi
                    ,ttt.tujuan_transaksi_2015
                    ,ttt.nama_penerima
                    ,ttt.jenis_no_identifikasi_penerima
                    ,ttt.nama_pembayar
                    ,ttt.jenis_no_identifikasi_pembayar
                    ,ttt.kode_swift_bank_pengirim
                    ,ttt.nomor_ft
                    ,ttt.f_id
                    ,ttt.negara_depository
                    ,ttt.no_identifikasi_penerima
                    ,ttt.jenis_identifikasi_pembayar
                    ,ttt.no_identifikasi_pembayar
                    ,ttt.kode_swift_bank_penerima
                    ,ttt.detail_transaksi
                    ,ttt.dokumen
                    ,ttt.gol_debitur_penerima
                    ,ttt.gol_debitur_pembayar
                    ,ttt.dokumen_pendukung_lld1
                    ,RIGHT('00' + CAST(MONTH(CAST(ttt.tanggal AS SMALLDATETIME)) AS VARCHAR(2)), 2) + '' + CAST(YEAR(CAST(ttt.tanggal AS SMALLDATETIME)) AS VARCHAR(4)) AS periode
                    ,ttt.flag_valid
                    ,mmll.Jenis_Rekening_lld2
                    ,mmll.Jenis_Valuta_lld2
                    ,mmll.Sandi_Negara_lld2
                    ,'153' + ttt.kode_cabang AS sandi_bank
                FROM TRX_TRANSAKSI_TEMP2 ttt
                LEFT JOIN MST_MAPPING_LLD1_LLD2 mmll
                    ON ttt.jenis_rekening = mmll.Jenis_Rekening_lld1
                        AND ttt.jenis_valuta = mmll.Jenis_Valuta_lld1
                        AND ttt.sandi_negara = mmll.Sandi_Negara_lld1
                WHERE Flag_Process = '0'
                    AND MONTH(CAST(ttt.tanggal AS SMALLDATETIME)) = '02'
                    AND YEAR(CAST(ttt.tanggal AS SMALLDATETIME)) = '2020'
                ) a
            LEFT JOIN MST_KURS mk
                ON mk.periode = a.periode
                    AND mk.sandi_valuta = a.jenis_valuta
            LEFT JOIN MST_KURS mk2
                ON mk2.periode = a.periode
                    AND mk2.sandi_valuta = 'USD'
            LEFT JOIN MST_POSISI mp
                ON a.Jenis_Rekening_lld2 = mp.Jenis_Rekening
                    AND a.Jenis_Valuta_lld2 = mp.Jenis_Valuta
                    AND a.Sandi_Negara_lld2 = mp.Sandi_Negara
                    AND a.sandi_bank = mp.Sandi_Bank
            ) b
        ) c
    ) d
LEFT JOIN MST_POSISI mp
    ON d.Jenis_Rekening_lld2 = mp.Jenis_Rekening
        AND d.Jenis_Valuta_lld2 = mp.Jenis_Valuta
        AND d.Sandi_Negara_lld2 = mp.Sandi_Negara
        AND d.sandi_bank = mp.Sandi_Bank
WHERE flag_valid = 'Y'
    AND (
        kode_cabang = 'ID0010002'
        OR d.kode_cabang IN (
            'ID0010002'
            ,'ID0010204'
            )
        )

在整数文字后加1.0 + (1.0 + (1 * (1.0 + 1.0))) // 3429ms 1.0 + (1.0 + (1.0 * (1.0 + 1.0))) // 5ms 后,许多1000 + ms的编译时表达式减少到10〜100ms。