优化Set操作——SUM中的CrossJoin

本文通过实际测试探讨了MDX中SET操作优化的方法,包括SUM中的CrossJoin使用、嵌套SUM中Set的放置位置以及计算项分解的影响。结果显示,某些传统观点可能需要重新评估。

今天看了《MDX Solutions with Microsoft SQL.Server Analysis Services 2005 and Hyperion Essbase 2nd Edition》书中关于优化SET操作的内容,并根据书中的内容作了一些测试,而测试结果有些符合书中的观点,有些则完全不同,真是让人有些意外。书中优化Set操作的主要观点是:

1. 优化Set操作的关键在于:把大的SET操作变成小的SET操作。
2. 由于CrossJoin代价(CPU、内存)巨大,所以最好用其他操作代替CrossJoin操作。

SUM中的CrossJoin
作者认为:要避免SUM一个包含多个CrossJoin的Set,你可以用其他的操作(比如嵌套SUM)进行替换。据此,我测试了一下
两组语句: 

WITH MEMBER MEASURES.ABC AS 
Sum (
    CrossJoin (
        Descendants (
            
[Customer].[Customer Geography].CurrentMember,
            
[Customer].[Customer Geography].[State-Province]
        ),
        Crossjoin (
            Descendants (
                
[Date].[Calendar].CurrentMember,
                
[Date].[Calendar].[Date]
            ),
            Descendants (
                
[Product].[Product Categories].CurrentMember,
                
[Product].[Product Categories].[Product Name]
            )
        )
    )
    ,[Measures].[Internet Sales Amount]-[Measures].[Internet Tax Amount]

  )
SELECT MEASURES.ABC ON 0 ,
[Customer].[Customer Geography].[Country].Members *  
[Date].[Calendar].[Calendar Year].MEMBERS * 
[Product].[Product Categories].[Category].MEMBERS
ON 1
FROM [Adventure Works]
WITH MEMBER MEASURES.ABC AS 
Sum (
    Descendants (
        
[Customer].[Customer Geography].CurrentMember,
        
[Customer].[Customer Geography].[State-Province]
    ),        
    
SUM(
        Descendants (
            
[Product].[Product Categories].CurrentMember,
            
[Product].[Product Categories].[Product Name]
        ),
        
SUM(
            Descendants (
                
[Date].[Calendar].CurrentMember,
                
[Date].[Calendar].[Date]
            )        
            ,[Measures].[Internet Sales Amount]-[Measures].[Internet Tax Amount]

        )                
    )    
)
SELECT MEASURES.ABC ON 0 ,
{
[Customer].[Customer Geography].[Country].Members} *  
[Date].[Calendar].[Calendar Year].Members * 
[Product].[Product Categories].[Category].Members
ON 1
FROM [Adventure Works]

以上语句中,作者认为第一个语句慢于第二个语句(理由是嵌套的SUM每次操作的SET更小),可实际的结果(测了10次)恰恰相反,第一个语句平均花费的时间51.654秒,而第二个语句平均花费的时间在55.912秒,这是何故呢?此外,书中认为在第二个语句的嵌套SUM中,如果把大的Set放在里面,这样会快一些。也就是说下面的语句比上面第二个语句要慢5%-20%。

WITH MEMBER MEASURES.ABC AS 
Sum (
    Descendants (
        
[Date].[Calendar].CurrentMember,
        
[Date].[Calendar].[Date]
    ),
    
SUM(
        Descendants (
            
[Product].[Product Categories].CurrentMember,
            
[Product].[Product Categories].[Product Name]
        ),      
        
SUM(
        Descendants (
            
[Customer].[Customer Geography].CurrentMember,
            
[Customer].[Customer Geography].[State-Province]
        ),    
            
[Measures].[Internet Sales Amount]-[Measures].[Internet Tax Amount]        )                
    )    
)
SELECT MEASURES.ABC ON 0 ,
{
[Customer].[Customer Geography].[Country].Members} *  
[Date].[Calendar].[Calendar Year].Members * 
[Product].[Product Categories].[Category].Members
ON 1
FROM [Adventure Works]

以上测试语句中,关于[Date].[Calendar].[Date]的Set其Turple个数在365左右,关于[Product].[Product Categories].[Product Name]的Set其Turple个数在几十个左右,而关于[Customer].[Customer Geography].[State-Province]的Set其成员个数大多在十几个左右

经过测试发现上面这条语句平均时间在57.858秒。也就是说,测试结果和书中的观点是一致的,只是幅度没有那么大。此外,我还尝试了一下这样的写法。

WITH 
MEMBER MEASURES.ABC 
AS 
Sum (
    
    CrossJoin (
        Descendants (
            
[Customer].[Customer Geography].CurrentMember,
            
[Customer].[Customer Geography].[State-Province]
        ),
        Crossjoin (
            Descendants (
                
[Date].[Calendar].CurrentMember,
                
[Date].[Calendar].[Date]
            ),
            Descendants (
                
[Product].[Product Categories].CurrentMember,
                
[Product].[Product Categories].[Product Name]
            )
        )
    ) 
AS MYABC

    ,
[Measures].[Internet Sales Amount]
)
-
Sum (    
    MYABC
    ,
[Measures].[Internet Tax Amount]
)
SELECT MEASURES.ABC ON 0 ,
[Customer].[Customer Geography].[Country].Members *  
[Date].[Calendar].[Calendar Year].MEMBERS * 
[Product].[Product Categories].[Category].MEMBERS
ON 1
FROM [Adventure Works]

上面语句的不同之处在于,把要计算的内容分散开来了,令人惊异的是,这个语句只要2-3秒种就能运行完成。


总结
由上面两次测试我们可以得出以下结论:
1)SUM中的CrossJoin并不一定会降低速度,书中的观点可能是错误的。看来MDX解析器对CrossJoin有很多有优化,在上面的测试中CrossJoin比嵌套的SUM要快8%左右。
2)嵌套SUM中,把大的SET放在里层的SUM中,这样速度能够快一些。上面的测试中,把小的Set放在里层比把大的Set放在里层慢3.5%。
3)在做SUM等统计计算时,如果能够把计算项分解到每个单独的Measure,这个时候性能提升非常明显,速度将会大大提高。上面的测试中,速度提高了20多倍。

### 完整的基于PaddlePaddle的昆虫识别项目 对于构建一个完整的基于PaddlePaddle框架的昆虫识别深度学习模型,可以遵循类似的结构化方法来实现。虽然提供的参考资料主要集中在PyTorch上[^1],这里将展示如何利用PaddlePaddle创建这样的应用。 #### 数据准备 首先需要收集并预处理用于训练的数据集。假设已经有一个包含多种昆虫图像及其标签的数据集: ```python import paddle from paddle.vision import transforms as T from paddle.io import Dataset import os from PIL import Image class InsectDataset(Dataset): def __init__(self, root_dir, transform=None): self.root_dir = root_dir self.transform = transform self.images = [] for label in sorted(os.listdir(root_dir)): path = os.path.join(root_dir, label) if not os.path.isdir(path): continue for fname in os.listdir(path): self.images.append((os.path.join(label, fname), int(label))) def __len__(self): return len(self.images) def __getitem__(self, idx): img_path, label = self.images[idx] image = Image.open(os.path.join(self.root_dir, img_path)).convert('RGB') if self.transform is not None: image = self.transform(image) return image, label transform = T.Compose([ T.Resize(256), T.CenterCrop(224), T.ToTensor(), ]) dataset = InsectDataset('./insects', transform=transform) dataloader = paddle.io.DataLoader(dataset, batch_size=32, shuffle=True) ``` #### 构建模型 接下来定义卷积神经网络架构。此处采用ResNet作为基础模型,并对其进行微调以适应特定的任务需求: ```python model = paddle.vision.models.resnet50(pretrained=True) num_ftrs = model.fc.in_features model.fc = paddle.nn.Linear(num_ftrs, num_classes=len(set([label for _, label in dataset]))) paddle.summary(model, (1, 3, 224, 224)) ``` #### 训练过程 设置损失函数、优化器以及评估指标来进行模型训练: ```python criterion = paddle.nn.CrossEntropyLoss() optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.001) for epoch in range(num_epochs): running_loss = 0.0 correct_predictions = 0 total_samples = 0 for images, labels in dataloader: outputs = model(images) loss = criterion(outputs, labels) optimizer.clear_grad() loss.backward() optimizer.step() predicted_labels = paddle.argmax(outputs, axis=-1) correct_predictions += sum(predicted_labels.numpy() == labels.numpy()) total_samples += len(labels) running_loss += loss.item() accuracy = correct_predictions / total_samples * 100. print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss/total_samples:.4f}, Accuracy: {accuracy:.2f}%') save_path = './saved_models/insect_recognition.pdparams' paddle.save(model.state_dict(), save_path) print("Model saved at", save_path) ``` 上述代码展示了从数据加载到模型保存的一个完整流程,在实际操作过程中还需要考虑更多细节如超参数调整等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值