首页 > 解决方案 > 繁琐的超时 PIVOT mssql

问题描述

我有一个令人作呕的类似于 PIVOT 的 SQL 查询(类似于运行 SQL Server 2000 的 PIVOT)

它使用一个子句选择大约 3500 列(可能更多)WHERE ,其中值在 1000 个元素的数组中。

注意: 查询在 MS SQL Server Management Studio 中运行良好...大约需要 4 分钟才能返回完整结果

SELECT prodIdxTbl.ID AS ID,
        prodIdxTbl.ProductID AS orProductCode,
        COALESCE(prodIdxTbl.Manufacturer, '') + '-' + COALESCE(prodIdxTbl.Partno, '') AS primaryId,
        prodIdxTbl.manufacturerid AS ManufacturerID1534,
        prodIdxTbl.Model AS Model1551,
        prodIdxTbl.Partno AS PartNo1581, 
    MIN(CASE WHEN (REPLACE(COALESCE(fieldNamesTbl.Text, '') + COALESCE(CONVERT(VARCHAR(10), fieldNamesTbl.ID), ''), ' ', ''))='CacheMemory1206' THEN attrsTbl.Data END) AS [CacheMemory1206], 
    MIN(CASE WHEN (REPLACE(COALESCE(fieldNamesTbl.Text, '') + COALESCE(CONVERT(VARCHAR(10), fieldNamesTbl.ID), ''), ' ', ''))='ISA1207' THEN attrsTbl.Data END) AS [ISA1207], 
    MIN(CASE WHEN (REPLACE(COALESCE(fieldNamesTbl.Text, '') + COALESCE(CONVERT(VARCHAR(10), fieldNamesTbl.ID), ''), ' ', ''))='MonoTonerLife1208' THEN attrsTbl.Data END) AS [MonoTonerLife1208], 
    MIN(CASE WHEN (REPLACE(COALESCE(fieldNamesTbl.Text, '') + COALESCE(CONVERT(VARCHAR(10), fieldNamesTbl.ID), ''), ' ', ''))='SpeedMonochrome1209' THEN attrsTbl.Data END) AS [SpeedMonochrome1209], 
    MIN(CASE WHEN (REPLACE(COALESCE(fieldNamesTbl.Text, '') + COALESCE(CONVERT(VARCHAR(10), fieldNamesTbl.ID), ''), ' ', ''))='RibbonLife1210' THEN attrsTbl.Data END) AS [RibbonLife1210], 
    MIN(CASE WHEN (REPLACE(COALESCE(fieldNamesTbl.Text, '') + COALESCE(CONVERT(VARCHAR(10), fieldNamesTbl.ID), ''), ' ', ''))='DataRate1211' THEN attrsTbl.Data END) AS [DataRate1211], 
    MIN(CASE WHEN (REPLACE(COALESCE(fieldNamesTbl.Text, '') + COALESCE(CONVERT(VARCHAR(10), fieldNamesTbl.ID), ''), ' ', ''))='1792x1344GraphicMode1212' THEN attrsTbl.Data END) AS [1792x1344GraphicMode1212], 
    MIN(CASE WHEN (REPLACE(COALESCE(fieldNamesTbl.Text, '') + COALESCE(CONVERT(VARCHAR(10), fieldNamesTbl.ID), ''), ' ', ''))='HorizontalFrequency1214' THEN attrsTbl.Data END) AS [HorizontalFrequency1214], 
    MIN(CASE WHEN (REPLACE(COALESCE(fieldNamesTbl.Text, '') + COALESCE(CONVERT(VARCHAR(10), fieldNamesTbl.ID), ''), ' ', ''))='ModemSpeeds1216' THEN attrsTbl.Data END) AS [ModemSpeeds1216], 
    MIN(CASE WHEN (REPLACE(COALESCE(fieldNamesTbl.Text, '') + COALESCE(CONVERT(VARCHAR(10), fieldNamesTbl.ID), ''), ' ', ''))='ScannerResolutionTrueHorizontal1217' THEN attrsTbl.Data END) AS [ScannerResolutionTrueHorizontal1217],
    ...
    MIN(CASE WHEN ('Feature' + (COALESCE(CONVERT(VARCHAR(10), featureIdxTbl.Sequence), '')))='Feature4' THEN featuresTbl.Name END) AS [Feature4], 
    MIN(CASE WHEN ('Feature' + (COALESCE(CONVERT(VARCHAR(10), featureIdxTbl.Sequence), '')))='Feature5' THEN featuresTbl.Name END) AS [Feature5], 
    MIN(CASE WHEN ('Feature' + (COALESCE(CONVERT(VARCHAR(10), featureIdxTbl.Sequence), '')))='Feature6' THEN featuresTbl.Name END) AS [Feature6], 
    MIN(CASE WHEN ('Feature' + (COALESCE(CONVERT(VARCHAR(10), featureIdxTbl.Sequence), '')))='Feature7' THEN featuresTbl.Name END) AS [Feature7], 
    MIN(CASE WHEN ('Feature' + (COALESCE(CONVERT(VARCHAR(10), featureIdxTbl.Sequence), '')))='Feature8' THEN featuresTbl.Name END) AS [Feature8], 
    MIN(CASE WHEN ('Feature' + (COALESCE(CONVERT(VARCHAR(10), featureIdxTbl.Sequence), '')))='Feature9' THEN featuresTbl.Name END) AS [Feature9] FROM [Data_Build].[dbo].[ProductIndex] AS prodIdxTbl
        INNER JOIN [IT_Data].[dbo].[Attributes] AS attrsTbl
            ON prodIdxTbl.ProductID = attrsTbl.ProductID
        INNER JOIN [FieldConfig].[dbo].[systemFieldNames] AS fieldNamesTbl
            ON attrsTbl.FieldNameID = fieldNamesTbl.ID
        LEFT JOIN [IT_Data].[dbo].[IndexFeature] AS featureIdxTbl
            ON prodIdxTbl.ProductID = featureIdxTbl.Productid
        LEFT JOIN [IT_Data].[dbo].[Features] AS featuresTbl
            ON featureIdxTbl.FeatureID = featuresTbl.ID
        WHERE CONVERT(DATETIME, prodIdxTbl.lastupdated) BETWEEN '2019-04-01 00:00:00.000' AND GETDATE() 
            AND prodIdxTbl.ProductID IN ('8200','8202','8203','8205','8210','8211','8212','8218','8219','8255','8273','8276','8277','8278','8287','8299','8313','8327','8417','8484','8499','8595','8596','8597','8600','8601','8602','8604','8608','8611','8612','8621','8625','8627','8629','8632','8634','8635','8636','8637','8638','8639','8640','8671','8677','8678','8679','8681','8731','8732','8739','8780','8783','8788','8791','8796','8798','8801','8804','8809','8833','8837','8852','8853','8855','8859','8872','8879','8880','8886','8889','8963','8965','8966','8968','8974','8975','8989','8995','8997','9000','9001','9002','9003','9004','9005','9006','9007','9009','9018','9027','9028','9059','9060','9061','9062','9063','9064','9065','9066','9067','9068','9080','9081','9082','9084','9085','9086','9087','9088','9089','9107','9108','9181','9189','9190','9191','9208','9210','9211','9212','9213','9214','9215','9216','9217','9218','9222','9223','9224','9225','9226','9227','9229','9230','9238','9250','9255','9256','9259','9260','9261','9262','9263','9267','9268','9269','9270','9313','9338','9339','9341','9342','9353','9373','9389','9394','9494','9496','9497','9499','9501','9519','9520','9523','9525','9527','9590','9592','9593','9600','9622','9623','9624','9634','9635','9638','9639','9640','9665','9688','9689','9690','9694','9695','9696','9703','9704','9705','9706','9707','9708','9744','9745','9747','9749','9751','9752','9753','9754','9786','9787','9788','9789','9790','9791','9793','9799','9802','9813','9822','9836','9837','9847','9872','9922','9923','9924','9963','9972','10004','10065','10066','10067','10068','10069','10070','10071','10072','10073','10074','10075','10076','10078','10079','10080','10083','10085','10087','10089','10118','10120','10122','10142','10146','10161','10183','10208','10213','10214','10222','10228','10233','10239','10242','10244','10248','10379','10563','10595','10603','10604','10606','10641','10643','10644','10648','10650','10673','10693','10697','10712','10713','10719','10720','10723','10731','10735','10738','10741','10742','10748','10749','10757','10760','10895','10899','10903','10904','10928','10929','10930','10931','10932','10933','10934','10935','10936','10937','10938','10939','10940','10941','10942','10943','10944','10945','10946','10947','10948','10949','10950','10951','10952','10953','10954','10955','10956','10957','10958','10959','10960','10961','10962','10963','11043','11053','11054','11135','11183','11185','11188','11189','11190','11191','11193','11194','11195','11196','11197','11198','11199','11200','11201','11202','11203','11204','11205','11206','11207','11208','11209','11210','11211','11212','11213','11214','11215','11216','11217','11218','11219','11220','11221','11222','11223','11224','11225','11226','11227','11228','11229','11230','11231','11232','11233','11234','11235','11236','11237','11238','11239','11240','11241','11242','11243','11244','11245','11246','11255','11256','11257','11275','11334','11774','11793','11794','11795','11796','11797','11798','11799','11800','11801','11802','11803','11804','11805','11806','11807','11808','11809','11810','11811','11812','11813','11814','11815','11816','11817','11818','11819','11820','11821','11822','11823','11824','11825','11826','11885','11886','11887','11888','11889','11890','11891','11892','11893','11894','11895','11896','11897','11898','11931','11932','12001','12002','12003','12004','12005','12006','12007','12008','12043','12073','12074','12075','12076','12077','12078','12079','12080','12081','12082','12083','12084','12085','12086','12087','12088','12089','12090','12091','12092','12093','12094','12095','12096','12097','12098','12099','12100','12101','12102','12103','12104','12105','12106','12107','12108','12109','12110','12111','12112','12113','12114','12115','12116','12117','12118','12119','12120','12121','12122','12123','12124','12125','12126','12127','12128','12129','12130','12131','12132','12133','12134','12135','12136','12137','12138','12139','12140','12141','12142','12143','12144','12145','12146','12147','12148','12149','12150','12151','12152','12153','12154','12155','12156','12157','12158','12159','12160','12161','12162','12163','12164','12165','12166','12167','12168','12169','12170','12171','12172','12173','12174','12175','12176','12177','12178','12179','12180','12181','12182','12183','12184','12185','12186','12187','12188','12189','12190','12191','12192','12193','12194','12195','12196','12197','12198','12199','12200','12201','12202','12203','12204','12205','12206','12207','12208','12209','12210','12211','12212','12214','12215','12216','12217','12218','12219','12220','12221','12222','12223','12224','12225','12226','12227','12228','12229','12230','12231','12232','12233','12234','12235','12236','12237','12238','12239','12240','12241','12242','12243','12244','12245','12246','12247','12248','12249','12250','12251','12252','12253','12254','12255','12256','12257','12258','12259','12260','12261','12262','12263','12264','12265','12266','12267','12268','12269','12270','12271','12272','12274','12275','12276','12277','12278','12279','12280','12281','12282','12283','12284','12285','12286','12287','12288','12289','12290','12291','12292','12293','12294','12295','12296','12297','12298','12299','12300','12301','12302','12303','12304','12305','12306','12307','12308','12309','12310','12311','12312','12313','12314','12315','12316','12317','12318','12319','12320','12321','12322','12323','12324','12326','12327','12328','12329','12330','12331','12332','12333','12334','12347','12348','12349','12350','12351','12353','12354','12355','12356','12358','12359','12360','12361','12362','12363','12364','12365','12366','12367','12368','12369','12370','12371','12372','12373','12374','12375','12376','12377','12378','12379','12380','12381','12382','12383','12384','12385','12386','12388','12391','12392','12393','12394','12401','12462','12463','12464','12483','12489','12491','12492','12493','12494','12496','12497','12498','12499','12500','12501','12502','12523','12524','12526','12528','12529','12530','12531','12532','12533','12534','12535','12536','12537','12538','12539','12540','12541','12542','12543','12544','12545','12546','12547','12549','12550','12551','12552','12553','12554','12555','12556','12557','12558','12559','12560','12561','12564','12570','12577','12578','12579','12580','12647','12662','12665','12710','12770','12775','12885','12909','13110','13111','13124','13128','13133','13137','13138','13139','13140','13141','13142','13143','13144','13145','13147','13149','13156','13157','13158','13780','13781','13782','13799','13817','13818','13819','13820','13821','13822','13823','13827','13829','13831','13834','13835','13836','13839','13841','13844','13847','13849','13850','13851','13852','13853','13854','13855','13856','13858','13885','13888','13889','13890','13891','13892','13893','13894','13895','13896','13897','13898','13899','13900','13901','13902','13909','13910','13911','13912','13914','13924','13925','13936','13937','13938','13955','13956','13957','13958','13959','13960','13961','13962','13963','13964','13965','13966','13967','13968','14261','14262','14263','14264','14270','14272','14279','14280','14281','14329','14330','14331','14332','14333','14334','14335','14336','14337','14338','14339','14340','14341','14342','14343','14345','14346','14347','14348','14349','14350','14351','14352','14353','14354','14355','14356','14357','14358','14359','14360','14361','14362','14363','14364','14365','14366','14367','14368','14369','14370','14371','14372','14373','14374','14375','14376','14377','14378','14379','14380','14385','14386','14387','14388','14389','14884','14889','14939','15015','15030','15045','15062','15093','15096','15098','15103','15148','15172','15173','15174','15177','15178','15179','15189','15191','15231','15232','15244')
        GROUP BY prodIdxTbl.ProductID,
            prodIdxTbl.ID,
            prodIdxTbl.manufacturerid,
            COALESCE(prodIdxTbl.Manufacturer, '') + '-' + COALESCE(prodIdxTbl.Partno, ''),
            prodIdxTbl.Model,
            prodIdxTbl.Partno

可悲的是,我们坚持使用 SQL Server 2000,但如果有人有任何简化此查询的想法,请提及。在过去的几年里,我对 SQL 一直在 NoSQL 领域感到非常生疏。

...只是它上面另外几千行类似的占位符。

index.js

const _ = require('lodash')
const fs = require('fs')
const sql = require('mssql')

const { getWantedAttributes,
    getWantedFeatures,
    runQuery
} = require('./lib')

require('dotenv').config()

const ids = fs.readFileSync('./src/data/ids.json', 'utf8')

const parsed = JSON.parse(ids)
const idChunks = _.chunk(parsed, 1000)

async function init() {
    const pool = new sql.ConnectionPool({
        user: process.env.MSSQL_USERNAME,
        password: process.env.MSSQL_PASSWORD,
        server: '<server_name>',
        parseJSON: true,
        requestTimeout: 300000, // 5 mins
        pool: {
            min: 1,
            max: 100,
            idleTimeoutMillis: 15000 // 15 secs
        }
    })

    try {
        const conn = await pool.connect()
        const wantedAttrs = await getWantedAttributes(conn)
        const wantedFeatures = await getWantedFeatures(conn)
        // Num of elements in query limited to 4096
        // Unsure how many Features there will be but 3000 is a safe num I think
        const attrsChunks = _.chunk(wantedAttrs, 3000)

        for await (const idChunk of idChunks) {
            for await (const aChunk of attrsChunks) {
                await runQuery({
                    pool,
                    chunks: {
                        attr: aChunk,
                        id: idChunk
                    },
                    wantedFeatures
                })
            }
        }
    } catch(err) {
        throw err
    }
}

lib.js

exports.runQuery = async function({ pool, chunks, wantedFeatures }) {
    return new Promise((resolve, reject) => {
        const request = pool.request({
            stream: true
        })
        const sqlQuery = buildSqlQuery(chunks.attr, wantedFeatures)
        const arr = JSON.stringify(chunks.id).replace(/"/g, "'").replace('[', '(').replace(']', ')')
        const queryEnd = `\n\tAND prodIdxTbl.ProductID IN ${arr}
        GROUP BY prodIdxTbl.ProductID,
            prodIdxTbl.ID,
            prodIdxTbl.manufacturerid,
            COALESCE(prodIdxTbl.Manufacturer, '') + '-' + COALESCE(prodIdxTbl.Partno, ''),
            prodIdxTbl.Model,
            prodIdxTbl.Partno`

        request.query(`${sqlQuery} ${queryEnd}`)

        request.on('recordset', handleColumns)
        request.on('row', handleRow)
        request.on('error', reject)
        request.on('done', resolve)
    })
}

我正在使用请求中的属性,正如返回的大型数据集的文档stream所强调的那样。

如果我在 VSCode 中一直调试到查询本身,应用程序会挂起大约 20 秒(我假设正在运行查询)然后吐出这个错误:

C:\Program Files\nodejs\node.exe --inspect-brk=32621 index.js 
Debugger listening on ws://127.0.0.1:32621/6c13f5a7-e858-43bc-ac87-aea8c616a1cb

For help, see: https://nodejs.org/en/docs/inspector

Debugger attached.

c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\value-parser.js:94

  readTextPointerNull(parser, type, textPointerNull => {
                                    ^

RangeError: Maximum call stack size exceeded
    at textPointerNull (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\value-parser.js:94:37)
    at readTextPointerNull (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\value-parser.js:42:5)
    at valueParse (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\value-parser.js:94:3)
    at next (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\token\row-token-parser.js:17:5)
    at value (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\token\row-token-parser.js:32:7)
    at readNChars (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\value-parser.js:412:12)
    at dataLength (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\value-parser.js:212:20)
    at awaitData (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\token\stream-parser.js:147:7)
    at Parser.awaitData (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\token\stream-parser.js:103:7)
    at Parser.readUInt16LE (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\token\stream-parser.js:144:10)

Waiting for the debugger to discon
RangeError: Maximum call stack size exceeded
    at textPointerNull (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\value-parser.js:94:37)
    at readTextPointerNull (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\value-parser.js:42:5)
    at valueParse (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\value-parser.js:94:3)
    at next (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\token\row-token-parser.js:17:5)
    at value (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\token\row-token-parser.js:32:7)
    at readNChars (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\value-parser.js:412:12)
    at dataLength (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\value-parser.js:212:20)
    at awaitData (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\token\stream-parser.js:147:7)
    at Parser.awaitData (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\token\stream-parser.js:103:7)
    at Parser.readUInt16LE (c:\Users\me\Documents\ProductAttributeRefresh\node_modules\tedious\lib\token\stream-parser.js:144:10)
nect...

我最初的想法是,这与查询的绝对规模有关。特别是评估的CASE陈述,但我不确定。

解决这个问题的最佳方法是什么?有没有办法进一步配置 mssql/tedious 来解决这个问题,或者有没有更好的方法来编写这个可怕的 SQL 语句。如果是后者,怎么做?

标签: node.jssql-serversql-server-2000tedious

解决方案


推荐阅读