我需要什么索引来加速和/或SQL查询
假设我有一个名为我需要什么索引来加速和/或SQL查询,sql,database,postgresql,indexing,Sql,Database,Postgresql,Indexing,假设我有一个名为customer的表,如下所示: +----+------+----------+-----+ | id | name | lastname | age | +----+------+----------+-----+ | .. | ... | .... | ... | CREATE TABLE customer (id int, name text, lastname text, age int); INSERT INTO customer SELECT g
customer
的表,如下所示:
+----+------+----------+-----+
| id | name | lastname | age |
+----+------+----------+-----+
| .. | ... | .... | ... |
CREATE TABLE customer (id int, name text, lastname text, age int);
INSERT INTO customer
SELECT g
, left(md5('foo'::text || g%500) , 3 + ((g%5)^2)::int)
, left(md5('bar'::text || g%1000), 5 + ((g%5)^2)::int)
, ((random()^2) * 100)::int
FROM generate_series(1, 30000) g; -- 30k rows for quick test case
我需要执行以下查询:
SELECT * FROM customer WHERE ((name = 'john' OR lastname = 'doe') AND age = 21)
我知道单列和多列索引是如何工作的,所以我创建了以下索引:
(name, age)
(lastname, age)
这就是我需要的所有索引吗
上述条件可以重新表述为:
... WHERE ((name = 'john' AND age = 21) OR (lastname = 'doe' AND age = 21)
但我不确定RDBMS有多聪明,如果这些索引是正确的,请将OR转换为两个联合查询:
SELECT * FROM Customer WHERE Age = 21 AND Name = 'John'
UNION
SELECT * FROM Customer WHERE Age = 21 AND LastName = 'Doe'
然后创建一个索引over(Age,Name)和另一个over(Age,LastName)。您的方法是合理的。这里有两个要素至关重要:
没有足够的数据来度量测试,您可以随时快速创建如下测试用例:
+----+------+----------+-----+
| id | name | lastname | age |
+----+------+----------+-----+
| .. | ... | .... | ... |
CREATE TABLE customer (id int, name text, lastname text, age int);
INSERT INTO customer
SELECT g
, left(md5('foo'::text || g%500) , 3 + ((g%5)^2)::int)
, left(md5('bar'::text || g%1000), 5 + ((g%5)^2)::int)
, ((random()^2) * 100)::int
FROM generate_series(1, 30000) g; -- 30k rows for quick test case
对于您的查询(重新格式化):
我会和你一起去
CREATE INDEX customer_age_name_idx ON customer (age, name);
CREATE INDEX customer_age_lastname_idx ON customer (age, lastname);
然而,取决于许多因素,一个包含所有三列和第一列的索引可能能够提供类似的性能。经验法则是创建尽可能少和尽可能多的索引
CREATE INDEX customer_age_lastname_name_idx ON customer (age, lastname, name);
在这种情况下,对(年龄、姓名)
的检查可能会较慢,但取决于第一列的选择性,这可能不会有多大影响
为什么age
在索引中排名第一?
这不是很重要,需要更深入的理解来解释。但是
对于两列索引customer\u age\u name\u idx
和customer\u age\u lastname\u idx
,列的顺序并不重要。详细信息和测试用例:
我仍然将age
放在第一位,以与我建议的第三个索引保持一致customer\u age\u lastname\u name\u idx
,其中列的顺序在多个方面都很重要:
最重要的,您的谓词(年龄,姓名)
和(年龄,姓氏)
都共享一列age
。B树索引(到目前为止)对前导列最有效,因此将age
放在首位对这两个方面都有好处
而且,不太重要,但仍然相关:由于索引页面的数据类型特征、对齐方式、填充和页面布局,索引的大小以这种方式更小
age
是一个4字节的整数
,必须在数据页中以4字节的倍数对齐<代码>文本
长度可变,没有对齐限制。由于“列俄罗斯方块”的规则,将整数放在第一位或最后更有效。我在代码>(姓氏、年龄、名字)<代码>(<代码>年龄>代码>中间)添加了另一个索引,以显示小提琴的“10%”更大。额外的填充不会丢失空间,这会导致较小的索引。而且大小很重要
出于同样的原因,最好对演示表中的列重新排序,如下所示:(id、age、name、lastname)
。如果您想了解原因,请从这里开始:
UNION
查询等价物?
请注意,
联合
查询可能返回相同的结果,也可能不返回相同的结果。它折叠重复的行,而您的原始行不折叠。即使您的表中没有完整的重复项,您仍然可以通过SELECT
列表中的一部分列看到这种效果。不要盲目地用联合
查询替换。无论如何也不会更快。为什么不对查询执行一些诊断?例如,如果您使用的是SQL Server,请使用执行计划并查看索引是否节省成本。除了将整个表放入索引之外,我认为没有多少优化可以完成query@Mihai我的表有更多的字段。。。这只是一个例子。@DarrenDavies不幸的是,我没有足够的数据来测量测试。。。我还不知道有任何工具可以告诉我这是否在我的数据库模式中工作。有关索引或性能的问题可能取决于你的Postgres版本。请随时提供。谢谢您的回复。我知道我可以做到,但这不是我的问题……是的,这些是索引。但建议使用UNION而不是OR。@RicardoPeres:“建议”对我来说是新闻。谁推荐的?您的是Access 2007(!),您的和是SQL Server。它们都涉及各自MS产品的实现细节,与Postgres(或其他SQL实现)无关。非常感谢您的回复;)我有一个简短的问题。。。在我的查询中,(年龄,姓名)
与(姓名,年龄)
,这有什么关系呢?@OscarMederos:好吧,这对两列索引来说并不重要。但它对3列索引很重要,对基础表也很重要。