Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>basic concept - use paralleism to speed this up. </p> <p>step 1 - give your threadpool enough threads to pull this off - ThreadPool.SetMinThreads(1024, 256);</p> <p>step 2 - use partitions. I use guids as Ids, i use the last to characters to split into 256 unique partitons (actually I group those into N subsets in my case 48 partitions)</p> <p>step 3 - insert using tasks, i use object pooling for table refs</p> <pre><code>public List&lt;T&gt; InsertOrUpdate(List&lt;T&gt; items) { var subLists = SplitIntoPartitionedSublists(items); var tasks = new List&lt;Task&gt;(); foreach (var subList in subLists) { List&lt;T&gt; list = subList; var task = Task.Factory.StartNew(() =&gt; { var batchOp = new TableBatchOperation(); var tableRef = GetTableRef(); foreach (var item in list) { batchOp.Add(TableOperation.InsertOrReplace(item)); } tableRef.ExecuteBatch(batchOp); ReleaseTableRef(tableRef); }); tasks.Add(task); } Task.WaitAll(tasks.ToArray()); return items; } private IEnumerable&lt;List&lt;T&gt;&gt; SplitIntoPartitionedSublists(IEnumerable&lt;T&gt; items) { var itemsByPartion = new Dictionary&lt;string, List&lt;T&gt;&gt;(); //split items into partitions foreach (var item in items) { var partition = GetPartition(item); if (itemsByPartion.ContainsKey(partition) == false) { itemsByPartion[partition] = new List&lt;T&gt;(); } item.PartitionKey = partition; item.ETag = "*"; itemsByPartion[partition].Add(item); } //split into subsets var subLists = new List&lt;List&lt;T&gt;&gt;(); foreach (var partition in itemsByPartion.Keys) { var partitionItems = itemsByPartion[partition]; for (int i = 0; i &lt; partitionItems.Count; i += MaxBatch) { subLists.Add(partitionItems.Skip(i).Take(MaxBatch).ToList()); } } return subLists; } private void BuildPartitionIndentifiers(int partitonCount) { var chars = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }.ToList(); var keys = new List&lt;string&gt;(); for (int i = 0; i &lt; chars.Count; i++) { var keyA = chars[i]; for (int j = 0; j &lt; chars.Count; j++) { var keyB = chars[j]; keys.Add(string.Concat(keyA, keyB)); } } var keySetMaxSize = Math.Max(1, (int)Math.Floor((double)keys.Count / ((double)partitonCount))); var keySets = new List&lt;List&lt;string&gt;&gt;(); if (partitonCount &gt; keys.Count) { partitonCount = keys.Count; } //Build the key sets var index = 0; while (index &lt; keys.Count) { var keysSet = keys.Skip(index).Take(keySetMaxSize).ToList(); keySets.Add(keysSet); index += keySetMaxSize; } //build the lookups and datatable for each key set _partitions = new List&lt;string&gt;(); for (int i = 0; i &lt; keySets.Count; i++) { var partitionName = String.Concat("subSet_", i); foreach (var key in keySets[i]) { _partitionByKey[key] = partitionName; } _partitions.Add(partitionName); } } private string GetPartition(T item) { var partKey = item.Id.ToString().Substring(34,2); return _partitionByKey[partKey]; } private string GetPartition(Guid id) { var partKey = id.ToString().Substring(34, 2); return _partitionByKey[partKey]; } private CloudTable GetTableRef() { CloudTable tableRef = null; //try to pop a table ref out of the stack var foundTableRefInStack = _tableRefs.TryPop(out tableRef); if (foundTableRefInStack == false) { //no table ref available must create a new one var client = _account.CreateCloudTableClient(); client.RetryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(1), 4); tableRef = client.GetTableReference(_sTableName); } //ensure table is created if (_bTableCreated != true) { tableRef.CreateIfNotExists(); _bTableCreated = true; } return tableRef; } </code></pre> <p>result - 19-22kops storage account maximum</p> <p>hit me up if your interested in the full source</p> <p>need moar? use multiple storage accounts!</p> <p>this is from months of trial and error, testing, beating my head against a desk. I really hope it helps.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload