用于选择首选糖果的高效SQL 2000查询

Bri*_*pie 3 sql database sql-server-2000

(我希望我能想出一个更具描述性的标题...如果你可以命名我询问的查询类型,建议一个或编辑这篇文章)

数据库:SQL Server 2000

样本数据(假设500,000行):

Name   Candy       PreferenceFactor
Jim    Chocolate   1.0
Brad   Lemon Drop   .9
Brad   Chocolate    .1
Chris  Chocolate    .5
Chris  Candy Cane   .5
499,995 more rows...

请注意,具有给定"名称"的行数是无限的.

期望的查询结果:

Jim    Chocolate   1.0
Brad   Lemon Drop   .9
Chris  Chocolate    .5
~250,000 more rows...

(由于克里斯对糖果手杖和巧克力同样偏爱,因此一致的结果就足够了).

问题: 如何从数据中选择名称,糖果,其中每个结果行包含唯一的名称,以便所选择的糖果具有每个名称的最高PreferenceFactor.(快速有效的答案首选).

桌子上需要什么索引?如果Name和Candy是另一个表的整数索引(除了需要一些连接)之外,它会有所不同吗?

Eri*_*ikE 6

您将发现以下查询优于给出的每个其他答案,因为它适用于单次扫描.这模拟了MS Access的First和Last聚合函数,这基本上就是你正在做的事情.

当然,你可能在CandyPreference表中有外键而不是名字.要回答你的问题,如果Candy和Name是另一个表中的外键,那么事实上是非常好的.

如果CandyPreferences表中有其他列,那么具有包含所涉及列的覆盖索引将产生更好的性能.使列尽可能小会增加每页的行数并再次提高性能.如果您经常使用WHERE条件进行查询以限制行,则覆盖WHERE条件的索引变得很重要.

彼得在这方面做得很好,但有一些不必要的复杂性.

CREATE TABLE #CandyPreference (
   [Name] varchar(20),
   Candy varchar(30),
   PreferenceFactor decimal(11, 10)
)
INSERT #CandyPreference VALUES ('Jim', 'Chocolate', 1.0)
INSERT #CandyPreference VALUES ('Brad', 'Lemon Drop', .9)
INSERT #CandyPreference VALUES ('Brad', 'Chocolate', .1)
INSERT #CandyPreference VALUES ('Chris', 'Chocolate', .5)
INSERT #CandyPreference VALUES ('Chris', 'Candy Cane', .5)

SELECT
   [Name],
   Candy = Substring(PackedData, 13, 30),
   PreferenceFactor = Convert(decimal(11,10), Left(PackedData, 12))
FROM (
   SELECT
      [Name],
      PackedData = Max(Convert(char(12), PreferenceFactor) + Candy)
   FROM CandyPreference
   GROUP BY [Name]
) X

DROP TABLE #CandyPreference
Run Code Online (Sandbox Code Playgroud)

除非性能至关重要,否则我实际上不推荐这种方法.执行它的"规范"方法是OrbMan的标准Max/GROUP BY派生表,然后连接到它以获取所选行.但是,当有多个列参与选择Max时,该方法开始变得困难,并且可以复制选择器的最终组合,也就是说,当没有列提供任意唯一性时,如此处的情况如果PreferenceFactor相同,我们使用名称.

编辑:最好提供一些更多的使用说明,以帮助提高清晰度,并帮助人们避免问题.

  • 作为一般经验法则,在尝试提高查询性能时,如果可以节省I/O,则可以进行大量额外的数学运算.保存整个表搜索或扫描会大大加快查询速度,即使使用所有转换和子字符串等也是如此.
  • 由于精度和排序问题,使用浮点数据类型可能是这种方法的一个坏主意.虽然除非您处理极大或极小的数字,否则您不应该在数据库中使用float.
  • 最佳数据类型是那些未打包并在转换为二进制或char后按相同顺序排序的数据类型.Datetime,smalldatetime,bigint,int,smallint和tinyint都直接转换为二进制并正确排序,因为它们没有打包.使用binary,避免使用left()和right(),使用substring()来获取可靠地返回其原始值的值.
  • 我利用Preference在此查询中只有一位小数点前面的数字,允许直接转换为char,因为小数点前总是至少有0.如果可能有更多数字,则必须对转换后的数字进行十进制对齐,以便正确排序.最简单的可能是乘以您的偏好等级,这样就没有小数部分,转换为bigint,然后转换为二进制(8).通常,数字之间的转换比char和另一种数据类型之间的转换更快,尤其是日期数学.
  • 注意空值.如果有,你必须将它们转换为某些东西,然后再返回.