当前位置: 首页 > 面试题库 >

SQL Server按列对查询

萧琛
2023-03-14
问题内容

我正在研究像亚马逊这样的产品过滤器(多面搜索)。我有一个具有属性(颜色,内存,屏幕)的表,如下所示:

ArticleID  PropertyID  Value
---------  ----------  ------------
1          1           Black
1          2           8 GB
1          3           15"
2          1           White
2          2           8 GB
3          3           13"

我必须根据选择的属性来选择文章。您可以为一个属性选择多个值(例如RAM:4 GB和8 GB),还可以选择多个属性(例如RAM和屏幕大小)。

我需要这样的功能:

SELECT ArticleID
FROM ArticlesProperties
WHERE (PropertyID = 2 AND Value IN ('4 GB', '8 GB'))
  AND (PropertyID = 3 AND Value IN ('13"'))

我曾经通过创建动态查询然后执行该查询来做到这一点:

SELECT ArticleID
FROM ArticlesProperties
WHERE PropertyID = 2 AND Value IN ('4 GB', '8 GB')

INTERSECT

SELECT ArticleID
FROM ArticlesProperties
WHERE PropertyID = 3 AND Value IN ('13"')

但我认为这不是好方法,必须有一些更好的解决方案。该表中有数百万个属性,因此有必要进行优化。

一个解决方案应该可以在SQL Server 2014 Standard Edition上运行,而无需一些附加组件或类似的搜索引擎solr

我在泡菜中,所以如果有人有任何想法或解决方案,我将非常感激。谢谢!


问题答案:

我做了一个片段,显示了我将按照的方式工作。索引的正确选择对于加快查询速度很重要。始终检查执行计划以进行索引调整。

笔记:

  • 该脚本使用临时表,但从本质上讲它们与常规表没有什么不同。除之外#select_properties,如果您打算使用脚本中概述的工作方式,则临时表应成为常规表。

  • 存储具有属性选择值(而不是实际选择值)的ID的商品属性。当这些表由SQL Server缓存时,这可以节省磁盘空间和内存。SQL Server将在内存中尽可能多地缓存表,以便更快地为select语句提供服务。

如果文章属性表太大,则SQL Server可能必须做磁盘IO才能执行select语句,这肯定会使语句变慢。

额外的好处是,对于查找,您查找的是ID(整数)而不是文本(VARCHAR的)。查找整数比查找字符串快得多。

  • 在表上提供合适的索引以加快查询速度。为此,优良作法是通过检查实际执行计划来分析查询。

我在下面的代码段中包含了几个这样的索引。根据文章属性表和统计信息中的行数,SQL Server将选择最佳索引以加快查询速度。

如果SQL Server认为查询缺少SQL语句的正确索引,则实际执行计划将显示您缺少索引。优良作法是当查询变慢时,通过检查SQL Server
Management Studio中的实际执行计划来分析这些查询。

  • 该代码段使用一个临时表来指定您要查找的属性:#select_properties。通过插入属性ID和属性选择值ID在表中提供条件。最终选择查询选择文章,其中至少一个属性选择值适用于每个属性。

您将在要选择文章的会话中创建此临时表。然后插入搜索条件,触发select语句,最后删除临时表。

CREATE TABLE #articles(
    article_id INT NOT NULL,
    article_desc VARCHAR(128) NOT NULL,
    CONSTRAINT PK_articles PRIMARY KEY CLUSTERED(article_id)
);

CREATE TABLE #properties(
    property_id INT NOT NULL, -- color, size, capacity
    property_desc VARCHAR(128) NOT NULL,
    CONSTRAINT PK_properties PRIMARY KEY CLUSTERED(property_id)
);

CREATE TABLE #property_values(
    property_id INT NOT NULL,
    property_choice_id INT NOT NULL, -- eg color -> black, white, red
    property_choice_val VARCHAR(128) NOT NULL,
    CONSTRAINT PK_property_values PRIMARY KEY CLUSTERED(property_id,property_choice_id),
    CONSTRAINT FK_values_to_properties FOREIGN KEY (property_id) REFERENCES #properties(property_id)
);

CREATE TABLE #article_properties(
    article_id INT NOT NULL,
    property_id INT NOT NULL,
    property_choice_id INT NOT NULL
    CONSTRAINT PK_article_properties PRIMARY KEY CLUSTERED(article_id,property_id,property_choice_id),
    CONSTRAINT FK_ap_to_articles FOREIGN KEY (article_id) REFERENCES #articles(article_id),
    CONSTRAINT FK_ap_to_property_values FOREIGN KEY (property_id,property_choice_id) REFERENCES #property_values(property_id,property_choice_id)

);
CREATE NONCLUSTERED INDEX IX_article_properties ON #article_properties(property_id,property_choice_id) INCLUDE(article_id);

INSERT INTO #properties(property_id,property_desc)VALUES
    (1,'color'),(2,'capacity'),(3,'size');

INSERT INTO #property_values(property_id,property_choice_id,property_choice_val)VALUES
    (1,1,'black'),(1,2,'white'),(1,3,'red'),
    (2,1,'4 Gb') ,(2,2,'8 Gb') ,(2,3,'16 Gb'),
    (3,1,'13"')  ,(3,2,'15"')  ,(3,3,'17"');

INSERT INTO #articles(article_id,article_desc)VALUES
    (1,'First article'),(2,'Second article'),(3,'Third article');

-- the table you have in your question, slightly modified
INSERT INTO #article_properties(article_id,property_id,property_choice_id)VALUES 
    (1,1,1),(1,2,2),(1,3,2), -- article 1: color=black, capacity=8gb, size=15"
    (2,1,2),(2,2,2),(2,3,1), -- article 2: color=white, capacity=8Gb, size=13"
    (3,1,3),        (3,3,3); -- article 3: color=red, size=17"

-- The table with the criteria you are selecting on
CREATE TABLE #select_properties(
    property_id INT NOT NULL,
    property_choice_id INT NOT NULL,
    CONSTRAINT PK_select_properties PRIMARY KEY CLUSTERED(property_id,property_choice_id)
);
INSERT INTO #select_properties(property_id,property_choice_id)VALUES
    (2,1),(2,2),(3,1); -- looking for '4Gb' or '8Gb', and size 13"

;WITH aid AS (  
    SELECT ap.article_id
    FROM #select_properties AS sp
         INNER JOIN #article_properties AS ap ON
            ap.property_id=sp.property_id AND
            ap.property_choice_id=sp.property_choice_id
    GROUP BY ap.article_id
    HAVING COUNT(DISTINCT ap.property_id)=(SELECT COUNT(DISTINCT property_id) FROM #select_properties)
    -- criteria met when article has a number of properties matching, equal to the distinct number of properties in the selection set
)
SELECT a.article_id,a.article_desc
FROM aid 
     INNER JOIN #articles AS a ON 
         a.article_id=aid.article_id
ORDER BY a.article_id;
-- result is the 'Second article' with id 2

DROP TABLE #select_properties;
DROP TABLE #article_properties;
DROP TABLE #property_values;
DROP TABLE #properties;
DROP TABLE #articles;


 类似资料:
  • 我想执行如下查询: 使用Spring的我应该使用这样的东西: 现在想象一下,我不想检查4列,而是检查10或20列,方法名会很长! 我在这个答案中看到,我可以使用在许多列中搜索相同的文本,但我希望每个列都有不同的文本值。 有什么方法可以缩短find方法并动态添加列(以及相应的值)吗? 谢谢

  • 本文向大家介绍详解sqlserver查询表索引,包括了详解sqlserver查询表索引的使用技巧和注意事项,需要的朋友参考一下 SELECT   索引名称=a.name  ,表名=c.name  ,索引字段名=d.name  ,索引字段位置=d.colid  需创建索引 例如: 根据某列判断是否有重复记录,如果该列为非主键,则创建索引 根据经常查询的列,创建索引 无须创建索引 字段内容大部分一样,

  • 本文向大家介绍深入分析SqlServer查询计划,包括了深入分析SqlServer查询计划的使用技巧和注意事项,需要的朋友参考一下 对于SQL Server的优化来说,优化查询可能是很常见的事情。由于数据库的优化,本身也是一个涉及面比较的广的话题, 因此本文只谈优化查询时如何看懂SQL Server查询计划。毕竟我对SQL Server的认识有限,如有错误,也恳请您在发现后及时批评指正。 首先,打

  • 我有一个清单,必须找到具体的对象。我必须按学生平均价值排序列表,并创建函数来搜索具有第二高价值的学生。如果与其他学生重复,则按函数返回较小的学生。这个任务的另一个要求(要妥善解决)是我不能创建任何对象。下面我留下了我正在使用的类的代码: 现在,我尝试通过对stream进行反向排序来解决这个问题,然后移除stream的第一个值,并比较stream的两个下一个对象并返回正确的一个。我可以使用for循环

  • 本文向大家介绍详解SQLServer和Oracle的分页查询,包括了详解SQLServer和Oracle的分页查询的使用技巧和注意事项,需要的朋友参考一下 不管是DRP中的分页查询代码的实现还是面试题中看到的关于分页查询的考察,都给我一个提示:分页查询是重要的。当数据量大的时候是必须考虑的。之前一直没有花时间停下来好好总结这里。现在又将Oracle视频中关于分页查询的内容看了一遍,发现很容易就懂了

  • 本文向大家介绍sqlserver分页查询处理方法小结,包括了sqlserver分页查询处理方法小结的使用技巧和注意事项,需要的朋友参考一下 sqlserver2008不支持关键字limit ,所以它的分页sql查询语句将不能用MySQL的方式进行,幸好sqlserver2008提供了top,rownumber等关键字,这样就能通过这几个关键字实现分页。 下面是本人在网上查阅到的几种查询脚本的写法: