7 ms·
> Overusing DISTINCT to “Fix” Duplicates Any time I see DISTINCT in a query I immediately become suspicious that the query author has an incomplete understandi
by EvanAnderson 1y ago
> Overusing DISTINCT to “Fix” Duplicates
Any time I see DISTINCT in a query I immediately become suspicious that the query author has an incomplete understanding of the data model, a lack of comprehension of set theory, or more likely both.
- Sesse__ 1y agoOr just doesn't know how to do semijoins in SQL, since they don't follow the same syntax as normal joins for whatever historical reason.
- leptons 1y agoAnd that's okay. Not every developer knows every single thing there is to know about every single tech. Sometimes you just need a solution, and someone with more specific knowledge can optimize later. How many non-database related mistakes would you make if you had to build every part of a system yourself?
- pessimizer 1y agoBut what if they don't know that they need your approval not to know things?
- bts89 1y agoThat’s almost always my experience too. Though fairly recently I learned that even with all the correct joins in place, sometimes adding a DISTINCT within a CTE can dramatically increase performance. I assume there’s some optimizations the query planner can make when it’s been guaranteed record uniqueness.
- yxhuvud 1y agoI've seen similar effects when changing a bunch of left outer joins to lateral joins with a limit 1 tacked on. The limit do nothing to the end result, but speed up the query by a factor of 1000..
- Breza 1y agoI agree with you. I also find that adding DISTINCT can sometimes make it easier for my colleagues to understand code, especially when I'm using multiple CTEs and it might be easy to miss a one-to-many join.
- wvbdmp 1y agoEh, sometimes you need a quick fix and it’s just extremely concise and readable. I’ll take an INNER JOIN over EXISTS (nice but insanely verbose) or CROSS APPLY (nice but slow) almost every time. Obviously you have to know what you’re dealing with, and I’m mostly talking about reporting, not perf critical application code. Distinct is also easily explained to users, who are probably familiar with Excel’s “remove duplicate rows”. It can also be great for exploring unfamiliar databases. I ask applicants to find stuff in a database they would never see by scrolling, and you’d be surprised how many don’t find it.
- Sesse__ 1y agoThe less verbose way of doing semijoins is by an IN subquery.
- wvbdmp 1y ago>subquery >less verbose Well… In any case, it depends. OP nicely guarded himself by writing “overusing”, so at that point his pro-tip is just a tautology and we are in agreement: not every use of DISTINCT is an immediate smell.
- Sesse__ 1y agoWhat do you mean? Here are your real alternatives for doing a semijoin (assuming ANSI SQL, no vendor extensions): SELECT * FROM t1 WHERE EXISTS ( SELECT * FROM t2 WHERE t2.x = t1.x ); SELECT * FROM t1 WHERE x IN ( SELECT x FROM t2 ); SELECT * FROM t1 JOIN ( SELECT DISTINCT x FROM t2 ) s1 USING (x); Now tell me which one of these is the less verbose semijoin? You could argue that you could fake a semijoin using SELECT DISTINCT * FROM t1 JOIN t2 USING (x); or SELECT * FROM t1 JOIN t2 USING (x) GROUP BY t1.*; but it doesn't give the same result if t1 has duplicate rows, or if there is more than one t2 matching t1. (You can try to fudge it by replacing * with something else, in which case the problem just moves around, since “duplicate rows” will mean something else.)
- wvbdmp 1y ago
- bandrami 1y agoIDK, "which ZIP codes do we have customers in?" seems like a reasonable thing to want to know
- mbb70 1y agoThe very next ask will be "order the zipcodes by number of customers" at which point you'll be back to aggregations, which is where you should have started
- sql_nitpicker 1y agodistinct seems like an aggregation to me
- deleted 1y ago[deleted]
- edoceo 1y agocount(id) group by post_code order by 1
- kristjansson 1y agoWhole seconds will have been wasted!
- wvbdmp 1y agoAnti-Patterns You Should Avoid: overengineering for potential future requirements. Are there real-life cases where you should design with the future in mind? Yes. Are there real-life cases where DISTINCT is the best choice by whatever metric you prioritize at the time? Also yes.
- RHSeeger 1y ago> Are there real-life cases where DISTINCT is the best choice by whatever metric you prioritize at the time Indeed, along that line, I would say that DISTINCT can be used to convey intent... and doing that in code is important. - I want to know the zipcodes we have customers in - DISTINCT - I want to know how many customers we have in each zipcode - aggregates Can you do the first with the second? Sure.. but the first makes it clear what your goal is.
- sigwinch28 1y agoOr it’s simply an indicator of a schema that has not been excessively normalised (why create an addresses_cities table just to ensure no duplicate cities are ever written to the addresses table?)
- valiant55 1y agoIt depends when you see it, but I agree that DISTINCT shouldn't be used in production. If I'm writing a one off query and DISTINCT gets me over the finish line sparing me a few minutes then that's fine.
- viraptor 1y agoWhich categories did the user post in? Which projects did the user interact with in the last week? That's all normal DISTINCT usage.
- ndsipa_pomu 1y agoThere's nothing wrong with using DISTINCT correctly and it does belong in production. The author is complaining about developers that just put in DISTINCT as a matter of course rather than using it appropriately.
- echelon 1y agoDISTINCT, as well as the other aggregation functions, are fantastic for offline analytics queries. I find a lot of use for them in reporting, non-production code.
- sgarland 1y agoBecause a city/region/state can be uniquely identified with a postal code (hell, in Ireland, the entire address is encapsulated in the postal code), but the reverse is not true. At scale, repeated low-cardinality columns matter a great deal.
- bdangubic 1y agosaying zipcodes uniquely identify city/state/region is like saying John uniquely identifies a human :)
- jmull 1y agoI'd be wary of overgeneralizing on that. I guess it depends on whose queries you're usually reading.
- RHSeeger 1y agoI think you're reading more into what was said than is really there > I immediately become suspicious All I read from that is, when DISTINCT is used, it's worth taking a look to make sure the person in question understands the data/query; and isn't just "fixing" a broken query with it. That doesn't mean it's wrong, but it's a "smell", a "flag" saying pay attention.
- ryandv 1y agoSet theory... There are self-identifying "senior software engineers" that cannot understand what even an XOR is, even after you draw out the entire truth table, all four rows.
- BuyMyBitcoins 1y agoI am surprised at common it is for software engineers to not treat booleans properly. I can’t tell you how many times if seen ‘if(IsFoo(X) != false)’ It never used to bug me as a junior dev, but once a peer pointed this out it became impossible for me to ignore.
- catlifeonmars 1y agoClearly the correct spelling is `if(X&IsFooMask != 0)` :)
- munchlax 1y agoPeople do that? This hurts my brain. if(IsFoo(X)) is clear and readable.
- furyofantares 1y agoThe most egregious one I saw, I was tracking down a bug and found code like this: bool x; ... if (x == true) { DoThing1(); } else if (x == false) { DoThing2(); } And of course neither branch was hit, because this is C, and the uninitialized x was neither 0 nor 1, but some other random value.
- tomjakubowski 1y agoSometimes this kind of thing happens after a few revisions of code, where in earlier versions the structure of the code made more sense: maybe several conditions which were tested and then, due to changing requirements, they coalesced into something which now reads as nonsense. When making a code change which touches a lot of places, it's not always obvious to "zoom out" and read the surrounding context to see if the structure of the code can be updated. The developer may be chewing through a grep list of a few dozen locations that need to be changed.
- dragonwriter 1y agoIn my experience, its nearly as often a problem with the design of the database as the query author.
- ryandv 1y agoPostgreSQL's `DISTINCT ON` extension is useful for navigating bitemporal data in which I want, for example, the latest recorded version of an entry, for each day of the year. There are few other legitimate use cases of the regular `DISTINCT` that I have seen, other than the typical one-off `SELECT DISTINCT(foo) FROM bar`.
- dotancohen 1y agoWithout DISTINCT ON (which I've never used) you can use a window function via the OVER clause with PARTITION BY. I'm pretty sure that's standard SQL.
- ryandv 1y agoYes, this is the implementation I have seen in other dialects.
- dotancohen 1y agoI've been told similar nasty things for adding LIMIT 1 to queries that I expect to return at most a single result, such as querying for an ID. But on large tables (at least in sqlite, mysql, and maybe postgress too) the database will continue to search the entire table after the given record was found.
- Guillaume86 1y agoOnly if your table is missing an unique index on that column, which it should have to enforce your assumption, so yeah LIMIT 1 is a code (or schema in the case) smell.
- dotancohen 1y agoIDs are typically unique primary key. But in my experience, adding LIMIT 1 would on average halve the time taken to retrieve the record. I'll test again, really the last time I tested that was two decades ago.
- buckle8017 1y agoYou are certainly doing something wrong if that's true. I'm curious, can you demo this?
- dotancohen 1y agoI'm curious as well to see if this still holds up. I'll try this week.
- EvanAnderson 1y agoThat seems like your RDBMS wasn't handling something right there or there wasn't a unique index on the column. Do you recall what the database server was?
- dotancohen 1y agoYes, I was using Mysql exclusively at the time. I don't recall which version. I also tested this once years later when doing a Python app with sqlite. Similar result, but admittedly that was not a very big table to begin with. I am meticulous with my database schemas, and periodically review my indexes and covering indexes. I'm no DBA, but I believe that the database is the only real value a codebase has, other than maybe a novel method here and there. So I put care into designing it properly and testing my assumptions.
- 9rx 1y agoOr believe more in Codd’s relational model than SQL’s tabulational model.
- mcv 1y agoIt's the exact opposite in Cypher. I'm currently working with some complex data in neo4j, and wondered why my perfectly fine looking queries were so slow, until I remembered to use DISTINCT. It's very easy to get duplicate nodes in your results, especially when you use variable length relationships, and DISTINCT is the only fix I'm aware of that fixes that.
- dleeftink 1y agoYeah, similarly combining distinct with recursive CTE's in SQL can be the difference between a n×n blowout or a performant graph walk that only visits nodes once.
- ch2026 1y agoOr maybe they’re on OLAP not OLTP.
- kpcyrd 1y agoSQL is somehow "ask two people, get three different opinions" for something as basic as: "given a BTreeMap<String, Vec<String>>, how do I do .keys() and .len()".
- qcnguy 1y agoSQL isn't very intuitive. Lots of people claim it is but then lots of people claim Haskell is, market outcomes suggest they are outliers. The big justification for its design is to enable compiler optimizations (query planning) but compilers can optimize imperative code very well too, so I wonder if you could get the same benefits with a language that's less declarative.
- fipar 1y agoI'm not sure I understand the part about set theory. If anything, a valid use of DISTINCT is if you want the result to be (closer to) a set, as otherwise (to your point, depending on the data model) you may get a bag instead. In fact, IIRC, using DISTINCT (usually bad for performance, btw) is an SQL advice by CJ Date in https://www.oreilly.com/library/view/sql-and-relational/9781491941164/ https://www.oreilly.com/library/view/sql-and-relational/9781...
- grumpylittleted 1y agoSo how do you "know" when you can safely omit DISTINCT for your shiny new query SELECT x FROM t ? Oh you looked the schema for t and it said x has a PRIMARY or UNIQUE constraint? Ah well two minutes after you looked at the schema Tom removed the UNIQUE constraint. Now your scratching your head when you get duplicates. Sql is a bag language not a set language. The contract with relation t is that if the runtime can find there rel t and attribute x it will return it. You may end up with rows or not, and you may end up with duplicates or not, and the type of x may change between subsequent execution. So if you want a set you need to say so using DISTINCT. At runtime the query planner will check the schema and if the attribute is UNIQUE or PRIMARY it will not have to do a deduplication.