SQL性能宽度与深度

时间:2013-09-20 03:36:57

标签: sql sql-server

我有一个客户表,其中包含有关客户偏好的信息,例如他是否希望收到简报等等。如果他/她想要收到简报,则该值存储在“customerNewsletter”列中并设置为true。但是,我有一些这些位值和参数位于自己的列中。我为每个客户存储日期,真/假,整数和tekst。

我发现大约80%的客户希望收到简报,这使得80%的价值设置为真。我现在将每个客户设置的值存储为false或true。如果我只需要将20%设置存储为假,该怎么办?

有一个列表,其中包含大约20个这样的参数,我可以将它们作为一个列(它们现在是),但我想知道是否有更好的方法。

所以我创建了3个表来保存这些参数值,一个保存实际值的参数表,一个保存值的名称的paramsNames表和一个将参数连接到customerID的参数表

SELECT 
customerParamsName as [Name],
customerParamText as [Text],
customerParamINT as [int],
customerParamsDateTime as [Date] 
FROM db14.customerParams
INNER JOIN db14.customerParam ON customerParamsChildID = customerParamID
INNER JOIN db14.customerParamsNames ON customerParamNameID = customerParamsNameID

这会给我

Name         Text         int   Date
Phonenumber  NULL   615164898   2013-09-20 00:00:00.000

有人能告诉我这是不是一个好方法,还是有更常见的方法来更有效地存储多类型参数?


在更多考虑之后

我创建了2个表

customerParam

paramID  paramNameID  ParamParentID  paramChildID  paramText    paramINT  paramDate
INT      TINYINT      INT            INT           varchar(24)  INT       DATETIME
PRIMARY               INDEXED

customerParamNames

paramNameID    paramName
TINYINT        VARCHAR(24)
PRIMARY

          1    'FirstName'
          2    'LastName'
          3    'Email Address'
          4    'Phonenumber'
          5    etc..

假设我想存储firstName和LastName

我在customerParam中为两个值创建记录;

paramID  paramNameID  ParamParentID  paramChildID  paramText    paramINT     paramDate
17456              1                               'John'
17467              2                               'Doo'
17468              1            752         17456
17469              2            752         17467

由于我希望更多出现名称'John',我将其存储为独立值,然后使用parentID / ChildID组合加入它。

和phoneNumber

17470              4            752                             31615164899            
17471              5            752                'me@here.com'

对于这个客户来说,phonenumber是非常明确的,我使用parentID将其直接加入到客户手中。电子邮件地址也是如此。

此时此解决方案看起来像是要走的路......我还在看xml方法,但我对如何使用存储在数据库中的XQuery和xmlDocuments没有很好的理解。 而且似乎有很多开销。

我将继续推进上述解决方案......直到有人给我一个更好的解决方案。

示例SQL

DECLARE @paramNames TABLE (paramNameID TINYINT, paramName varchar(24))

DECLARE @param TABLE (paramID INT, paramNameID TINYINT, paramParentID INT, paramChildID INT, paramText varchar(24), paramINT INT, paramDate datetime)

INSERT INTO @paramNames VALUES ( 1, 'firstname')
INSERT INTO @paramNames VALUES ( 2, 'lastname')
INSERT INTO @paramNames VALUES ( 3, 'emailaddress')
INSERT INTO @paramNames VALUES ( 4, 'phonenumber')

select * from @paramNames

INSERT INTO @param VALUES (1, 1, Null, Null, 'John' , Null, Null)
INSERT INTO @param VALUES (2, 2, Null, Null, 'Doo' , Null, Null)
INSERT INTO @param VALUES (3, 1, 752, 1, Null , Null, Null)
INSERT INTO @param VALUES (4, 2, 752, 2, Null , Null, Null)
INSERT INTO @param VALUES (5, 4, 752, Null, Null , 615164899, Null)
INSERT INTO @param VALUES (5, 3, 752, Null, 'me@here.com' , Null, Null)

select 
a.paramParentID, b.paramName, c.paramText, c.paramINT, c.paramDate
from @param a
inner join @paramNames b on a.paramNameID = b.paramNameID
inner join @param c on a.paramChildID = c.paramID
UNION ALL
select 
a.paramParentID, b.paramName, a.paramText, a.paramINT, a.paramDate
from @param a
inner join @paramNames b on a.paramNameID = b.paramNameID
WHERE paramParentID IS NOT NULL
AND paramChildID IS NULL

给出结果

paramParentID   paramName       paramText   paramINT    paramDate
752             firstname       John        NULL        NULL
752             lastname        Doo         NULL        NULL
752             phonenumber     NULL        615164899   NULL
752             emailaddress    me@here.com NULL        NULL

2 个答案:

答案 0 :(得分:2)

如果您考虑到性能和灵活性,我会稍微改变一下。

USE Test;

CREATE TABLE Customers
(
    CustomerID INT NOT NULL CONSTRAINT PK_Customers 
                 PRIMARY KEY CLUSTERED IDENTITY(1,1)
    , CustomerName NVARCHAR(255)
);

CREATE TABLE CustomersReceivingEmails
(
    CustomerID INT NOT NULL CONSTRAINT FK_CustomerID 
                 FOREIGN KEY REFERENCES Customers (CustomerID)
                 ON DELETE CASCADE ON UPDATE CASCADE
    , EmailAddress NVARCHAR(255) NOT NULL
    CONSTRAINT PK_CustomersReceivingEmails 
                 PRIMARY KEY CLUSTERED (CustomerID, EmailAddress)
);

INSERT INTO Customers (CustomerName) VALUES ('Max');
INSERT INTO Customers (CustomerName) VALUES ('Mike');

INSERT INTO CustomersReceivingEmails (CustomerID, EmailAddress) 
        VALUES (1, 'us@them.com');
INSERT INTO CustomersReceivingEmails (CustomerID, EmailAddress) 
        VALUES (1, 'us@me.com');

/* ALL Customers */
SELECT * FROM Customers;

/* Only customers who wish to receive Emails, allows a given customer 
    to have multiple email addresses */
SELECT C.CustomerName, E.EmailAddress 
FROM Customers C 
    INNER JOIN CustomersReceivingEmails E ON C.CustomerID = E.CustomerID
ORDER BY C.CustomerName, E.EmailAddress;

SELECT返回如下行:

enter image description here

这允许Customers表包含所有客户,无论他们对电子邮件的偏好如何。

对于想要接收电子邮件的客户,CustomersReceivingEmails表格有Customers.CustomerID的外键。

答案 1 :(得分:1)

您的第二个解决方案是通常所说的Entity-Attribute-Value数据模型的变体。这种方法似乎很灵活。但是,它本质上在模式中生成模式,并且随着属性数量的增加而查询非常慢

如果您要存储大量相同的值,请查看columnstore indexes。它们在选择性较低的情况下很好地工作(许多行和只有少量不同的值)