<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="333795" data-post-id="333795">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="seva" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/seva/120/22920_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  seva
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>great points <a class="mention" href="/u/garrison" rel="nofollow">@garrison</a>.</p>
<p>I do need to check for uniqueness on the contents of the JSONB column as well, maybe indeed unusual.</p>
<p>But very good point that even looking for presence of an existing record means that having an index will be beneficial in terms of performance, so there’s more of a case for adding the index.</p>
<p>Interesting idea with storing sha256 of jsonb column to improve index performance!</p>
<p>Thank you for your thoughts <img src="https://forum.elixirforum.com/images/emoji/apple/blush.png?v=15" title=":blush:" class="emoji" alt=":blush:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="333795" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-do-get-or-insert-by-in-ecto-without-race-condition/22160/22">Post #21</a>
	                </div>
	            </div>
              <div id="likers-container-333795" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="333795"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #21"></div>
  </section>
</div>
    <div class="postbit" id="333802" data-post-id="333802">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="benwilson512" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/120/1457_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  benwilson512
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Craft GraphQL APIs in Elixir with Absinthe</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Notably one challenge with sha256ing JSON is that JSON objects can be equivalent in a JSON sense but not in a byte wise sense because the order of keys does not matter for object equivalence, but will produce different hashes.</p>
<p>Is the whole JSON object relevant for uniqueness or just some value inside of it?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="333802" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-do-get-or-insert-by-in-ecto-without-race-condition/22160/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-333802" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="333802"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #22"></div>
  </section>
</div>
    <div class="postbit" id="333804" data-post-id="333804">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="seva" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/seva/120/22920_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  seva
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Excellent catch. In my case the whole JSON object is relevant (I store varied chunks of external API responses).</p>
<p>I didn’t end up going with this solution for now anyways, still waiting to get my ass bitten by a race condition before bothering adding uniqueness constraint (for my use case it’s not a biggie if I get a duplicate once in a blue moon anyway).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="333804" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-do-get-or-insert-by-in-ecto-without-race-condition/22160/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-333804" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="333804"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #23"></div>
  </section>
</div>
    <div class="postbit" id="333841" data-post-id="333841">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="garrison" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  garrison
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="benwilson512" data-post="23" data-topic="22160">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/48/1457_2.png" class="avatar"> benwilson512:</div>
<blockquote>
<p>Notably one challenge with sha256ing JSON is that JSON objects can be equivalent in a JSON sense but not in a byte wise sense because the order of keys does not matter for object equivalence, but will produce different hashes.</p>
</blockquote>
</aside>
<p>Aha, this did cross my mind but I really didn’t think he was actually checking the JSON blobs themselves for uniqueness so I didn’t elaborate <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>Indeed, you can be bitten not only by key order but also by whitespace, and probably other weird stuff with encoding. In crypto(graphy) in particular this gets messy because deriving an HMAC from computed state (like re-encoded JSON) is a big no-no (it tends to lead to vulns), which is why you get all that weird cursed json-in-json stuff with JWTs for example.</p>
<p>Ideally you would be using the hash just to check whether a value has changed, meaning that even if you get a “false positive” the worst case is just overwriting the JSON with itself. This assumes there is some other unique identifier at play, though, or you will just start accumulating similar-but-not-the-same blobs. Of course, this might also be true without the hash (I don’t know how postgres implements equality on JSON columns).</p>
<p>If it came to it, nested sorting and then re-encoding the JSON and hashing it as a string should be fine (unless you’re doing cryptography stuff, in which case hopefully you know better).</p>
<aside class="quote no-group" data-username="seva" data-post="24" data-topic="22160">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/seva/48/22920_2.png" class="avatar"> seva:</div>
<blockquote>
<p>still waiting to get my ass bitten by a race condition before bothering adding uniqueness constraint (for my use case it’s not a biggie if I get a duplicate once in a blue moon anyway).</p>
</blockquote>
</aside>
<p>Honestly for your use case I’d be more worried about the nasty performance you’re going to get if you ever accumulate enough rows in that table to start actually stressing the database. Obviously if the table is small none of this matters anyway (and you could just index the column in full without worry, too).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="333841" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-do-get-or-insert-by-in-ecto-without-race-condition/22160/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-333841" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="333841"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #24"></div>
  </section>
</div>
    <div class="postbit" id="333844" data-post-id="333844">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="garrison" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  garrison
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>A full explanation is of course rather involved, but I’ll try my best to answer this.</p>
<aside class="quote no-group" data-username="tfwright" data-post="20" data-topic="22160">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tfwright/48/20299_2.png" class="avatar"> tfwright:</div>
<blockquote>
<p>My understanding is two connections requesting an exclusive lock on a table in order to perform this kind of “find or insert” will protect against race conditions.</p>
</blockquote>
</aside>
<p>You are correct that locking <em>the entire table</em> would technically protect against this, but that’s not what was being discussed. As the post you cited detailed, the discussion was about <em>row-level</em> locks, and full table locks are really only relevant in the case of huge operations that touch the entire table.</p>
<p>Databases like postgres have “multi-granularity” locks, meaning (tautologically) that they can lock at different granularities. There are full-database locks (not sure if postgres has these), table locks, page locks (you’re not allowed to use these in postgres but they exist internally), and of course row locks.</p>
<p>When you run <code>SELECT ... FOR UPDATE</code> you get a row lock for each row returned by the select - in Ecto this is <code>lock(query, "FOR UPDATE")</code>. These are pessimistic, and they will block any other transaction which tries to modify the row until after the transaction with the locks commits or aborts (I will note for posterity that this can lead to deadlock). These row locks <em>would, ostensibly</em> allow one to execute an atomic <code>get_or_insert</code>. Except they don’t, because the row doesn’t exist yet. So there’s nothing to lock. That’s it - that’s all you have to understand about why it doesn’t work.</p>
<aside class="quote no-group" data-username="tfwright" data-post="20" data-topic="22160">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tfwright/48/20299_2.png" class="avatar"> tfwright:</div>
<blockquote>
<p>I am wondering how to square what you’re describing with the point <a class="mention" href="/u/jeremyjh" rel="nofollow">@jeremyjh</a> makes above, which <a href="https://forum.elixirforum.com/t/how-to-do-get-or-insert-by-in-ecto-without-race-condition/22160/7" rel="nofollow">specifically distinguishes isolation level from locking</a>.</p>
</blockquote>
</aside>
<p>I brought up isolation levels because I was proposing a working solution to the problem, namely that this <code>get_or_insert</code> trick <em>would</em> happen to work under SERIALIZABLE isolation. That comment doesn’t exactly “distinguish isolation level from locking” (though they are of course distinguished). Jeremy was just correcting another comment which incorrectly stated that serializable isolation locks the entire table (it doesn’t).</p>
<p>The purpose of serializable isolation is to execute concurrent transactions with an outcome that is <em>as if</em> they were run in <em>some</em> serial order, one after another. This is important for ridding ones code of nasty race conditions, as this thread has so helpfully demonstrated <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>One of the things (but <em>not</em> the only thing) needed to achieve serializable isolation is something called a “predicate lock”. It is not sufficient to lock individual rows for exactly the reason we have discovered: they don’t always exist when you try to read them! So instead you need to lock on the “idea” that there <em>could</em> be a row there. In practice you lock on a range, like “all employees with salary between 100 and 200”, which may in turn lock on pages containing those ranges in an index, or something like that (it’s obviously rather implementation-specific).</p>
<p>The predicate locking that you get from serializable isolation just happens to be enough to solve this problem. There are other, weirder, anomalies that require the full SSI algorithm (or strict two-phase locking, another algorithm), and if you want to understand them, that paper I linked really is gold.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="333844" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-do-get-or-insert-by-in-ecto-without-race-condition/22160/26">Post #25</a>
	                </div>
	            </div>
              <div id="likers-container-333844" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="333844"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #25"></div>
  </section>
</div>
    <div class="postbit" id="333863" data-post-id="333863">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tfwright" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tfwright/120/20299_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tfwright
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="garrison" data-post="26" data-topic="22160">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>You are correct that locking <em>the entire table</em> would technically protect against this, but that’s not what was being discussed. As the post you cited detailed, the discussion was about <em>row-level</em> locks, and full table locks are really only relevant in the case of huge operations that touch the entire table.</p>
</blockquote>
</aside>
<p>Interesting, are you saying that a table lock will work here but is not the most optimal solution?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="333863" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-do-get-or-insert-by-in-ecto-without-race-condition/22160/27">Post #26</a>
	                </div>
	            </div>
              <div id="likers-container-333863" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="333863"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #26"></div>
  </section>
</div>
    <div class="postbit" id="333874" data-post-id="333874">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="benwilson512" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/120/1457_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  benwilson512
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Craft GraphQL APIs in Elixir with Absinthe</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>“Not optimal” sort of understates it honestly, it is a textbook bottleneck. You’re only allowing a single reader / writer to the table at a time (at least, for any reader / writer that has to perform that sort of operation).</p>
<p>The inherent tension with all of these solutions is that at 0 scale they’re all fine. At any scale they’re all sorta bad because we are working with an arbitrary JSON blob, with the unique index being the best option because you need it anyway to make the <code>get_by</code> part scale, so may as well make it unique and upsert.</p>
<p>Ultimately I sort of what to revisit the concept of “Find or create by JSON blob”. Is there really nothing more unique? What is it?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="333874" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-do-get-or-insert-by-in-ecto-without-race-condition/22160/28">Post #27</a>
	                </div>
	            </div>
              <div id="likers-container-333874" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="333874"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #27"></div>
  </section>
</div>
    <div class="postbit" id="333876" data-post-id="333876">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tfwright" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tfwright/120/20299_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tfwright
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="benwilson512" data-post="28" data-topic="22160">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/48/1457_2.png" class="avatar"> benwilson512:</div>
<blockquote>
<p>“Not optimal” sort of understates it honestly, it is a textbook bottleneck. You’re only allowing a single reader / writer to the table at a time (at least, for any reader / writer that has to perform that sort of operation).</p>
</blockquote>
</aside>
<p>Yes, well there’s always a bottle neck, no? I guess my “real” question is more like, assuming you need this, what the best balance of simplicity and performance? I’ve used a table lock for this before and never ran into any issues with it. Probably because it was a very specific operation that was rarely used. But if there is an approach that’s comparably simple but a lot more performant then of course I want to be aware. I love postgres, but I find that fairly often its API/docs don’t make it easy to spot the right place to start for something like this. So then people avoid involving it at all.</p>
<p>But also yes, my guess is for this particular problem (and most similar use cases) there is probably a not-too-hard way to implement a proper unique index.  In my case, I had a client demand an upsert but refuse to enforce uniqueness. <img src="https://forum.elixirforum.com/images/emoji/apple/person_shrugging.png?v=15" title=":person_shrugging:" class="emoji" alt=":person_shrugging:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="333876" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-do-get-or-insert-by-in-ecto-without-race-condition/22160/29">Post #28</a>
	                </div>
	            </div>
              <div id="likers-container-333876" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="333876"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #28"></div>
  </section>
</div>
    <div class="postbit" id="333878" data-post-id="333878">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="benwilson512" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/120/1457_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  benwilson512
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Craft GraphQL APIs in Elixir with Absinthe</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I think we’re mostly in agreement here.</p>
<aside class="quote no-group" data-username="tfwright" data-post="29" data-topic="22160">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tfwright/48/20299_2.png" class="avatar"> tfwright:</div>
<blockquote>
<p>Probably because it was a very specific operation that was rarely used.</p>
</blockquote>
</aside>
<p>As I said, at 0 scale basically anything works. Heck, even just “hope the race condition doesn’t happen” might be just fine.</p>
<aside class="quote no-group" data-username="tfwright" data-post="29" data-topic="22160">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tfwright/48/20299_2.png" class="avatar"> tfwright:</div>
<blockquote>
<p>But also yes, my guess is for this particular problem (and most similar use cases) there is probably a not-too-hard way to implement a proper unique index.</p>
</blockquote>
</aside>
<p>If you’re not doing JSONB specifically I don’t super duper understand what would be even vaguely hard about a unique index. <code>create unique index on my_table (my_unique_column)</code> and just call it a day. You knock out two birds with one stone:</p>
<ol>
<li>Your <code>get_by</code> will stay fast</li>
<li>You are guaranteed to not get &gt; 1 rows back.</li>
</ol>
<p>This will take you all the way from “Hope the race condition doesn’t happen” up through tens of millions of rows without even really thinking about it and while yes, there is always a bottleneck, 8 orders of magnitude worth of scale is pretty dang good as a default approach.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="333878" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-do-get-or-insert-by-in-ecto-without-race-condition/22160/30">Post #29</a>
	                </div>
	            </div>
              <div id="likers-container-333878" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="333878"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #29"></div>
  </section>
</div>
    <div class="postbit" id="333880" data-post-id="333880">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tfwright" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tfwright/120/20299_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tfwright
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="benwilson512" data-post="30" data-topic="22160">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/48/1457_2.png" class="avatar"> benwilson512:</div>
<blockquote>
<p>As I said, at 0 scale basically anything works. Heck, even just “hope the race condition doesn’t happen” might be just fine.</p>
</blockquote>
</aside>
<p>We might not agree here. I’ll take a performance penalty over a race condition any day. But I’ll also take a performance penalty just to avoid complexity, until it’s no longer practical.</p>
<aside class="quote no-group" data-username="benwilson512" data-post="30" data-topic="22160">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/48/1457_2.png" class="avatar"> benwilson512:</div>
<blockquote>
<p>If you’re not doing JSONB specifically I don’t super duper understand what would be even vaguely hard about a unique index.</p>
</blockquote>
</aside>
<p>It’s not hard in almost any case, as I said above, that’s mostly all I have ever used. If you’re concerned I’m advocating people jump straight to table locks, that’s not it at all. I’m more interested in the case I described above, where I was expressly forbidden from enforcing uniqueness. Silly and rare, but it’s actually happened to me. To the best of my current knowledge, a table lock is the best approach there, but I’d be happy to learn something better for next time.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="333880" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-do-get-or-insert-by-in-ecto-without-race-condition/22160/31">Post #30</a>
	                </div>
	            </div>
              <div id="likers-container-333880" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="333880"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #30"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/22160/load_more?page=4">Load more posts (4 remaining)</a>
</div></template></turbo-stream>