我有下表:
CREATE TABLE sample (
id INT
);
假设我有x行。
我做SELECT COUNT(1) FROM sample
,然后把x拿回来。
现在说我这样做:
SELECT COUNT(1)
FROM sample AS s1
JOIN sample AS s2
ON s2.id < s1.id;
这使我后退了(x*(x-1))/2行。
现在说我这样做:
SELECT COUNT(1)
FROM sample AS s1
JOIN sample AS s2
ON s2.id < s1.id
LEFT JOIN sample AS s3
ON s3.id < s2.id;
这让我得了x*(x-1)*(x-2)/6+(x-1)
。如果我执行了JOIN而不是LEFT JOIN,我将返回x*(x-1)*(x-2)/6
行。
SELECT COUNT(1)
FROM sample AS s1
JOIN sample AS s2
ON s2.id < s1.id
LEFT JOIN sample AS s3
ON s3.id < s2.id
LEFT JOIN sample AS s4
ON s4.id > s2.id
AND s4.id < s1.id;
我不知道我会回到多少排。
顺便说一句,最后一个查询的目的是给你第二个id。例如
SELECT s1.id
FROM sample AS s1
JOIN sample AS s2
ON s2.id < s1.id
LEFT JOIN sample AS s3
ON s3.id < s2.id
LEFT JOIN sample AS s4
ON s4.id > s2.id
AND s4.id < s1.id
WHERE s3.id IS NULL
AND s4.id IS NULL;
当id有与之相关联的用户,并且您试图为特定用户或所有用户找到第二个id时,它会更有用。我只是想了解它是如何渐进地执行的。
有什么想法吗?谢谢
这里有一种不太数学的方法来查找您要查找的多项式。你可以用你制作的小提琴来找到前几个数字的结果。之后,您可以使用WolframAlpha。
结果:x^4/24-x^3/4+35*x^2/24-13*x/4+3。
读到你对性能和big-O表示法的评论,我突然明白了你在追求什么——或者至少我想我明白了。
n是表中元素的数量,第一次选择的性能为O(n):
SELECT COUNT(1) FROM sample -> O(n)
第二次选择时,您是对的。它给出(n*(n1))/2行。因为方程的平方部分对于大n来说是主导的,所以可以去掉减法(-1)和除法(/2)。性能为O(n²)。回到您的SQL查询,这意味着您可以简单地删除JOIN子句中的条件。可以简化为:
SELECT COUNT(1) FROM sample, sample => O(n²)
第三次选择中的LEFT JOIN将具有相同的效果。一个简单的左联接ON(s1.id<s2.id)将返回额外的n*(-1)行,而INNER联接不会返回这些行。在big-O表示法中,无论是否使用WHERE子句,它仍然是O(n²)。所以LEFT JOIN与否,都是一样的。因此,您的第三个选择将跟随O(n³),表示大n。
SELECT COUNT(1) FROM sample, sample, sample => O(n³)
根据先前的理解,很容易看出您的第四次SELECT归结为
SELECT COUNT(1) FROM sample, sample, sample, sample => O(n^4)
很容易看出O()是如何跟随样本表的记录数和自联接数的。
唯一需要回答的问题是"WHERE rightside.id为NULL"如何影响系统。根据定义,"SELECT FROM a,LEFT JOIN b where b.key IS NULL"只能返回与表a中相同数量或更少的行。因此,选择可以简化为:
SELECT COUNT(1) FROM sample, sample, const, const => O(n²)
数据库是否真的会这样执行,或者它是否会构建完整的笛卡尔乘积,然后消除绝大多数行,这取决于数据库查询优化器的实现,并且必须根据特定的数据库实现来回答。最坏的情况是,数据库将执行如下操作:
SELECT COUNT(1) FROM sample, sample, sample, sample => O(n^4)
我希望这能回答你的问题。如果没有,我很抱歉。。。但即使在那时,我仍然很喜欢分析您的查询:)
您是想识别两个相同名称的条目,还是想了解查询如何运行的技术解释?
我为dups设置了一个SQLfiddle,并放入了一些带有一个重复值的行。它通过查询当前行的值来查找valu列中的重复值,并使用count()函数来确定是否有多个值。
如果你愿意,你可以运行连接查询,但我不会跳过两个连接。:)