Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我需要什么索引来加速和/或SQL查询_Sql_Database_Postgresql_Indexing - Fatal编程技术网

我需要什么索引来加速和/或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)。

您的方法是合理的。这里有两个要素至关重要:

  • Postgres可以通过位图索引扫描非常有效地组合多个索引

  • 当只涉及索引的前导列时,B树索引的使用是最有效的

  • 测试用例 如果您
    没有足够的数据来度量测试,您可以随时快速创建如下测试用例:

    +----+------+----------+-----+
    | 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列索引很重要,对基础表也很重要。