数据透视表汇总上的Excel性能

时间:2019-07-29 23:50:46

标签: c# c++ excel xml libreoffice

在使用Excel时,我总是对Excel进行以下两个聚合操作的效果感到惊讶:

  1. 日期/时间汇总。
  2. 不区分大小写的聚合。

Excel如何实现该性能?它们是否存储其他数据结构以用于与枢轴相关的信息和聚合?是否在任何地方或在哪里可以找到更多有关此文档的信息?我已经看过Libreoffice的源代码,但是实际产品在聚合/数据透视性能上甚至不接近Excel。


如果了解Excel的人可以分享更多有关Excel为实现此性能而使用的低级聚合行为或结构的信息,例如,他们是否两次存储了任何标签,都可以在其本机中共享一次案例,并曾经降低以进行汇总?虽然我知道这个问题过于笼统,而不是关于代码答案本身,而是从概念上讲,但我希望答案可以为在excel样式的聚合上优化性能的方法提供良好的参考。


根据ARGeo的一些建议,我注意到了几件事-

(1)有两个与数据透视缓存有关的文件-定义(字段级信息):

enter image description here

(2)和记录(行/单元格级别信息)-

enter image description here

然后有几个问题:

  • Excel如何确定何时按原样存储值以及何时将其存储为共享记录。例如,为什么B2中的“ LifeLock”(大小写混合的字符串)的值按原样存储,而F2中的“ AZ”的值却按sharedItems(v =“ 0”)的形式存储?
  • 内部C / C ++ Struct上是否有任何信息供Excel使用内存用于其ivotCache(而不是作为存储的各种XML文档)?
  • 是否存在有关Excel内部如何使用字段级别存储的“帮助者信息”的信息?例如,此信息:

<cacheField name="numEmps" numFmtId="0"><sharedItems containsString="0" containsBlank="1" containsNumber="1" containsInteger="1" minValue="0" maxValue="20000"/></cacheField>

2 个答案:

答案 0 :(得分:8)

数据透视表的效果基于Pivot Cache。尽管有关此主题的信息很少(我是说缺少官方文档),但我发现了一些有趣的文章和MS文档。

定义

Pivot Cache是一个特殊的存储区域,用于保存数据透视表记录

enter image description here

  

创建Pivot Table时,Excel会获取源数据的副本并将其存储在Pivot Cache中。 Pivot Cache保留在Excel的内存中。您看不到它,但这是构建数据透视表时数据透视表引用的数据。

     

This enables Excel to be very responsive to changes in the Pivot Table but it can also double the size of your file 。毕竟,数据透视缓存只是源数据的重复,因此有意义的是文件大小可能会加倍。

请使用此link和此link作为参考,以获取更多信息。

此外,您可以阅读Pivot Cache in Excel 101Excel Pivot Cache 101帖子,以了解其含义和副作用。

以下是一些VB代码段以及如何使用PivotCache object的示例。

这是用C#编写的代码,它允许您使用一些Pivot Tables创建一个Excel工作簿,当然,该工作簿使用Pivot Cache

System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Excel = Microsoft.Office.Interop.Excel;
using System.IO;
using System.Diagnostics;
using System.Configuration;
using System.Data.SqlClient;
using System.Data;

namespace ConsoleApplication1 {

    class Program {

        static void Main(string[] args) {

            Excel.Application objApp;
            Excel.Workbook objBook;
            Excel.Sheets objSheets;
            Excel.Workbooks objBooks;

            string command = (@"SELECT * FROM dbo.Client");

            using (SqlConnection connection = new SqlConnection(GetConnectionStringByName("CubsPlus"))) {

                DataTable data = new DataTable();

                try {
                    connection.Open();
                }
                catch (Exception e) {
                    StackTrace st = new StackTrace(new StackFrame(true));
                    StackFrame sf = st.GetFrame(0);
                    Console.WriteLine (e.Message + "\n" + "Method" + sf.GetMethod().ToString() + "\n" + "Line" + sf.GetFileLineNumber().ToString());
                }
                try {
                    data = DataTools.SQLQueries.getDataTableFromQuery(connection, command);

                    if (data == null) {
                        throw new ArgumentNullException();
                    }
                }
                catch (Exception e) {

                    StackTrace st = new StackTrace(new StackFrame(true));
                    StackFrame sf = st.GetFrame(0);
                    Console.WriteLine (e.Message + "\n" + "Method" + sf.GetMethod().ToString() + "\n" + "Line" + sf.GetFileLineNumber().ToString());
                }

                objApp = new Excel.Application();

                try {     
                    objBooks = objApp.Workbooks;
                    objBook = objApp.Workbooks.Add(Missing.Value);
                    objSheets = objBook.Worksheets;

                    Excel.Worksheet sheet1 = (Excel.Worksheet)objSheets[1];
                    sheet1.Name = "ACCOUNTS";
                    string message = DataTools.Excel.copyDataTableToExcelSheet(data, sheet1);

                    if (message != null) {
                        Console.WriteLine("Problem importing the data to Excel");
                        Console.WriteLine(message);
                        Console.ReadLine();
                    }

                    //CREATE A PIVOT CACHE BASED ON THE EXPORTED DATA
                    Excel.PivotCache pivotCache = objBook.PivotCaches().Add(Excel.XlPivotTableSourceType.xlDatabase,sheet1.UsedRange);

                    Console.WriteLine(pivotCache.SourceData.ToString());

                    Console.ReadLine();

                    //WORKSHEET FOR NEW PIVOT TABLE
                    Excel.Worksheet sheet2 = (Excel.Worksheet)objSheets[2];
                    sheet2.Name = "PIVOT1";

                    //PIVOT TABLE BASED ON THE PIVOT CACHE OF EXPORTED DATA
                    Excel.PivotTables pivotTables = (Excel.PivotTables)sheet2.PivotTables(Missing.Value);
                    Excel.PivotTable pivotTable = pivotTables.Add(pivotCache, objApp.ActiveCell, "PivotTable1", Missing.Value, Missing.Value);

                    pivotTable.SmallGrid = false;
                    pivotTable.TableStyle = "PivotStyleLight1";

                    //ADDING PAGE FIELD
                    Excel.PivotField pageField = (Excel.PivotField)pivotTable.PivotFields("ParentName");
                    pageField.Orientation = Excel.XlPivotFieldOrientation.xlPageField;

                    //ADDING ROW FIELD
                    Excel.PivotField rowField = (Excel.PivotField)pivotTable.PivotFields("State");
                    rowField.Orientation = Excel.XlPivotFieldOrientation.xlRowField;

                    //ADDING DATA FIELD
                    pivotTable.AddDataField(pivotTable.PivotFields("SetupDate"), "average setup date", Excel.XlConsolidationFunction.xlAverage);

                    ExcelSaveAs(objApp, objBook, @"J:\WBK");

                    objApp.Quit();
                }     
                catch (Exception e) {

                    objApp.Quit();
                    Console.WriteLine(e.Message);
                    Console.ReadLine();
                }
            }
        }

        static string ExcelSaveAs(Excel.Application objApp, Excel.Workbook objBook, string path) {
            try {
                objApp.DisplayAlerts = false;
                objBook.SaveAs(path, Excel.XlFileFormat.xlExcel7, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Excel.XlSaveAsAccessMode.xlNoChange, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
                objApp.DisplayAlerts = true;
                return null;
            }
            catch (Exception e) {
                StackTrace st = new StackTrace(new StackFrame(true));
                StackFrame sf = st.GetFrame(0);
                return (e.Message + "\n" + "Method" + sf.GetMethod().ToString() + "\n" + "Line" + sf.GetFileLineNumber().ToString());
            }
        }
        static string GetConnectionStringByName(string name) {
            //ASSUME FAILURE
            string returnValue = null;

            //Look for the name in the connectionStrings section
            ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings[name];

            // If found, return the connection string
            if (settings != null) {
                returnValue = settings.ConnectionString;
            }
            return returnValue;
        }
    }
}

这是用VB编写的代码,可让我们为选定的Pivot Cache创建一个新的Pivot Table

Sub SelPTNewCache()

    Dim wsTemp As Worksheet
    Dim pt As PivotTable

    On Error Resume Next
    Set pt = ActiveCell.PivotTable

    If pt Is Nothing Then
        MsgBox "Active cell is not in a pivot table"
    Else
        Set wsTemp = Worksheets.Add

        ActiveWorkbook.PivotCaches.Create( _
            SourceType:=xlDatabase, _
            SourceData:=pt.SourceData).CreatePivotTable _
            TableDestination:=wsTemp.Range("A3"), _
            TableName:="PivotTableTemp"

        pt.CacheIndex = wsTemp.PivotTables(1).CacheIndex

        Application.DisplayAlerts = False
        wsTemp.Delete
        Application.DisplayAlerts = True
    End If

exitHandler:
        Set pt = Nothing

End Sub

enter image description here

  

1。。在您的asd.js文件中,包含以下元素:

s代表一个字符串值

n代表数字值

d代表日期值

x代表索引值

v表示值本身

因此,让我们用人类语言翻译此表的F2单元格中包含的数据

enter image description here

<x v="0"/>

0的值是存储美国州的缩写的字符串数组中的zero index。该数组中的第一个索引为我们检索Arizona。我不知道为什么下一行的单元格包含小写的az,而其他所有单元格都包含大写的AZ,但我确定它与Shared Record无关。

  

2。。我没有发现内部C / C ++ Struct的任何有用信息,Excel对其透视缓存使用内存。

最后,

  

3。。这是一个LINK,其中包含有关第三个问题的“帮助者信息”的有用信息。

P.S。

关于大O符号

  

Big O notation在计算机科学中用于描述算法的性能或复杂性。 Big O特别描述了最坏的情况,可用于描述算法所需的执行时间或所使用的空间(在内存或磁盘上)。 Big O notation是根据输入大小来衡量程序复杂度的度量。

  • O(1) 代表始终在同一时间执行的算法,而不管输入数据集的大小如何。

  • O(N) 代表算法,其性能与输入数据集的大小成线性比例并成正比。

  • O(N*N) 代表其性能与输入数据集的大小平方成正比的算法。

  • T(N) = O(log N) 代表其性能取决于对数时间的算法。对数时间的算法通常在binary trees上的操作中或使用二进制搜索时找到。

但是严格的排序算法严格 O(N log N) 。具有这种效率的算法示例可以是合并排序 将数组分成两半,通过对它们进行递归调用对其进行排序,然后将结果合并回去

这是一个抽象的C#代码段,显示了 O(N log N) 算法的工作原理(可以使用相同的方法来创建数据透视表):

public static int[] MergeSort(int[] inputItems, int lowerBound, int upperBound) {
    if (lowerBound < upperBound) {
        int middle = (lowerBound + upperBound) / 2;
        MergeSort(inputItems, lowerBound, middle);
        MergeSort(inputItems, middle + 1, upperBound);

        int[] leftArray = new int[middle - lowerBound + 1];
        int[] rightArray = new int[upperBound - middle];

        Array.Copy(inputItems, lowerBound, leftArray, 0, middle - lowerBound + 1);
        Array.Copy(inputItems, middle + 1, rightArray, 0, upperBound - middle);

        int i = 0;
        int j = 0;
        for (int count = lowerBound; count < upperBound + 1; count++) {
            if (i == leftArray.Length) {
                inputItems[count] = rightArray[j];
                j++;
            }
            else if (j == rightArray.Length) {
                inputItems[count] = leftArray[i];
                i++;
            }
            else if (leftArray[i] <= rightArray[j]) {
                inputItems[count] = leftArray[i];
                i++;
            }
            else {
                inputItems[count] = rightArray[j];
                j++;
            }
        }
    }
    return inputItems;
}

答案 1 :(得分:4)

  • 数据透视表与流行的看法不只是Excel 功能,但存在于许多以表格形式处理的应用程序中 结构化的数值数据–数据透视表是可视化的 数据聚合一般概念的交互结果取决于 在类别上。
  • 数据透视表始终链接到它们源自的数据。
  • 创建数据透视表时,Excel将建立特殊的内存缓存 在后台包含您的数据。此数据透视表缓存存储一个 源数据范围内数据的副本。
  • 数据透视表引用相同的数据源,则共享数据透视表缓存 数据范围。这有助于减小文件大小,并防止我们 刷新共享相同源数据范围的每个数据透视表。

enter image description here

  • 数据透视表和数据透视表缓存之间的关系可以得到 复杂。特别是由于数据透视表缓存存储在 背景,并且无法查看正在共享哪些数据透视表 工作簿中的数据透视缓存。

Anatomy of Spreadsheet File