Diesen Artikel finden Sie hier auch in deutscher Sprache.
This post is the second part of „Loading tables based on foreign key topology using Biml – Part 1: Linear loads“ and should be regarded as an add-on. Therefore, we recommend to read part 1 first, if you haven’t done so yet.
After the first excitment about how easy it actually was to take care of that topology, you might ask yourself: Why does it have to run linear? That takes way too long. And you’re right – and it doesn’t have to.
All we need to do is:
– Create a list of all the tables that we’ve already loaded (which will be empty at that point)
– Identify all tables that do not reference any other tables
– Load these tables, each followed by all tables that only reference this single table – recursively and add them to list of loaded tables
– Once that is done, load all tables that are referencing multiple tables where all required tables have been loaded before – and again, add them to the list
– Repeat this until no table is left to load (or for a maximum of 10 times in this example)
– If, for whichever reason, any tables are left, load them sequentially using the TopoSort function:
<#@ template tier="4" language="VB"#>
<#@ code file="../Code/TopologySort.vb" #>
<#@ import namespace="TopologySort" #>
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Packages>
<Package Name="03_Load_Parallel" ConstraintMode="Linear" PackageSubpath="<#= OutputPath #>">
<Tasks>
<ExecutePackage Name="Recreate Tables">
<ExternalFile ExternalFilePath="<#= OutputPath #>\01_Create.dtsx"/>
</ExecutePackage>
<Container Name="Load tables without reference and immediate descendants" ConstraintMode="Parallel">
<Tasks>
<# for each t as asttablenode in rootnode.tables.where(function(r) r.columns.OfType(Of AstTableColumnTableReferenceNode)().Count+r.columns.OfType(Of AstMultipleColumnTableReferenceNode)().Count = 0) #>
<Container Name="Load <#= t.name #>" ConstraintMode="Linear">
<Tasks>
<#= CallBimlScript("05_Recursion.biml",t,LoadedTables) #>
</Tasks>
</Container>
<# next #>
</Tasks>
</Container>
<# do while rootnode.tables.where(function(e) not loadedtables.contains(e.name) and not e.columns.OfType(Of AstMultipleColumnTableReferenceNode).Where(function(c) c.foreigntable.name <> e.name and not loadedtables.contains(c.foreigntable.name) ).count > 0 and not e.columns.OfType(Of AstTableColumnTableReferenceNode).Where(function(m) m.foreigntable.name <> e.name and not loadedtables.contains(m.foreigntable.name) ).count > 0).Any and level < 10
Level += 1
loadabletables = rootnode.tables.where(function(e) not loadedtables.contains(e.name) and not e.columns.OfType(Of AstMultipleColumnTableReferenceNode).Where(function(c) c.foreigntable.name <> e.name and not loadedtables.contains(c.foreigntable.name) ).count > 0 and not e.columns.OfType(Of AstTableColumnTableReferenceNode).Where(function(m) m.foreigntable.name <> e.name and not loadedtables.contains(m.foreigntable.name) ).count > 0).ToList #>
<Container Name="Load possible tables - Level <#= Level #>" ConstraintMode="Parallel">
<Tasks>
<# for each tbl as asttablenode in loadabletables #>
<#= CallBimlScript("06_Dataflow.biml",tbl,loadedtables) #>
<# next #>
</Tasks>
</Container>
<# loop
if loadedtables.count < rootnode.tables.count then #>
<Container Name="Load leftover tables" ConstraintMode="Linear">
<Tasks>
<# for each t as asttablenode in rootnode.tables.TopoSort.where(function(r) not loadedtables.contains(r.name)) #>
<#= CallBimlScript("06_Dataflow.biml",t,LoadedTables) #>
<# next #>
</Tasks>
</Container>
<# end if #>
</Tasks>
</Package>
</Packages>
</Biml>
The first step, which loads all tables which do not reference other tables as well as their descendants is actually not necessary – you could remove it and still, the logic would pick up all tables (just creating a couple more steps in the second loop). The reason I built that into this solution is to show you another pretty cool thing: You can actually use CallBimlScript within a called Biml script. You can even call the same script again – which will result in the desired effect of recursion:
<#@ template language="VB" designerbimlpath="Biml/Packages/Package/Tasks" #>
<#@ property name="tbl" type="AstTableNode" #>
<#@ property name="LoadedTables" type="List (of String)" #>
<#= CallBimlScript("06_Dataflow.biml",tbl,LoadedTables) #>
<# for each t as asttablenode in rootnode.tables.where(function(r) r.columns.OfType(Of AstTableColumnTableReferenceNode)().Count+r.columns.OfType(Of AstMultipleColumnTableReferenceNode)().Count =1).where(function(e) e.columns.OfType(Of AstTableColumnTableReferenceNode)().first.foreigntable.name = tbl.name ) #>
<#= CallBimlScript("05_Recursion.biml",t,LoadedTables) #>
<#next #>
Depending on your machine and data, this load should be much faster that the sequential load from the first example – still ensuring our data’s integrity!
Any questions or comments? We’d love to hear from you at !
Further Information on Biml in English can be found on our English Biml Page.
Happy Biml’ing!