在最大解码函数上创建索引
Posted
技术标签:
【中文标题】在最大解码函数上创建索引【英文标题】:Creating Index on Max Decode function 【发布时间】:2015-10-14 03:14:49 【问题描述】:我们有一个表,它以属性名称和值对的形式存储用户信息。在这个表上,我们通过使用 decode 将行转换为列来创建一个视图。 MAX(DECODE(attribute_name,'FirstName',attribute_Value)) FirstName
CREATE OR REPLACE FORCE VIEW vw_get_userinfo
("USER_ID", "FIRSTNAME", "LASTNAME", "USEREMAIL",
"STREET", "CITY", "STATE", "ZIPCODE", "COUNTRY")
AS
SELECT
t.user_id,
t.firstname,
t.lastname,
t.useremail,
t.street,
t.city,
t.state,
t.country
FROM (WITH
tempattributes AS (SELECT
user_id,
attribute_name,
attribute_value
FROM user_details)
SELECT
user_id,
MAX(DECODE(attribute_name, 'FirstName', attribute_value)) FirstName,
MAX(DECODE(attribute_name, 'LastName', attribute_value)) LastName,
MAX(DECODE(attribute_name, 'UserEmail', attribute_value)) UserEmail,
MAX(DECODE(attribute_name, 'Street', attribute_value)) Street,
MAX(DECODE(attribute_name, 'City', attribute_value)) City,
MAX(DECODE(attribute_name, 'State', attribute_value)) State,
MAX(DECODE(attribute_name, 'ZipCode', attribute_value)) Zipcode,
MAX(DECODE(attribute_name, 'Country', attribute_value)) Country
FROM tempattributes
GROUP BY user_id
) t
在解释计划期间,使用名字字段查询时会执行完整扫描。在这种情况下,基于函数的索引不适用,因为索引不适用于按函数分组。有什么方法可以在FirstName
属性上创建索引?
任何帮助将不胜感激。
【问题讨论】:
如果您需要性能建议,您应该显示整个查询。 谢谢@GordonLinoff。我已包含查询。 我在查询中看不到任何过滤谓词。您正在投影表中的所有行。显然需要full table scan
。当您基于column
过滤数据时,在该列上创建index
是有意义的。如果您基于expression
过滤数据,则需要在该列上创建function-based index
。您不需要用于投影行的索引。发布解释计划。见How to create and display EXPLAIN PLAN
感谢@LalitKumarB。当我检查以下查询的解释计划时,它显示范围扫描,因为已为 user_details 表上的 user_id 字段创建了索引。 SELECT * FROM VW_GET_USERINFO WHERE USER_ID='XYZ'。但是当我们使用 FIRST_NAME 作为过滤器时,由于没有创建索引,它会导致全扫描。
@RealChembil 同样,您在静态表列或包含静态表列的表达式上创建索引。
【参考方案1】:
“有什么方法可以在 FirstName 属性上创建索引?”
没有。索引建立在表列上。您的视图下的表具有(键,值)对的通用结构。对于应用程序开发人员来说,这种方法看起来既灵活又省时,但代价是用户在性能不佳时付出了代价。
当然,您最终仍然定义了一组固定的属性,只是结构在视图中而不是表中表示。那么,您真正获得了哪些灵活性?
如果您不想定义一组固定的属性,无论出于何种原因,您都应该选择一种受支持的方法,例如 XML 或 12c 中的 JSON。至少它们的属性是可索引的。 Find out more.
【讨论】:
【参考方案2】:这可能对性能没有帮助,但您可以将查询编写为:
SELECT user_id,
MAX(DECODE(attribute_name,'FirstName',attribute_Value)) as FirstName,
MAX(DECODE(attribute_name,'LastName',attribute_Value)) as LastName,
MAX(DECODE(attribute_name,'UserEmail',attribute_Value)) as UserEmail,
MAX(DECODE(attribute_name,'Street',attribute_Value)) as Street,
MAX(DECODE(attribute_name,'City',attribute_Value)) as City,
MAX(DECODE(attribute_name,'State',attribute_Value)) as State,
MAX(DECODE(attribute_name,'ZipCode',attribute_Value)) as ZipCode,
MAX(DECODE(attribute_name,'Country',attribute_Value)) as Country
FROM user_details
GROUP BY user_id;
(注意:比起DECODE()
,我更喜欢CASE
,但我将保留你原来的逻辑。)
Oracle 有一个很好的优化器,但是嵌套的with
可能会影响它,所以它可能会执行得更好。您还可以尝试在user_details(user_id, attribute_name, attribute_value)
上建立索引,看看是否能提高性能。
【讨论】:
以上是关于在最大解码函数上创建索引的主要内容,如果未能解决你的问题,请参考以下文章
sql 在分区表上创建基于函数的索引时解决方法ORA-01652
SQL Server 索引视图:无法创建聚集索引,因为选择列表包含聚合函数结果的表达式