There are a couple of points:
- could you please publish the source code of the class, and not the SQL script? The fact is that the command
CREATE INDEX BITMAP_INDEX_ST_SEARCH_VISIT_BLOOD_TYPE_CODE ON SQLUser.ST_SEARCH_VISIT (BLOOD_TYPE_CODE)
creates a regular index, not a bitmap index as expected. I'm afraid my code may not match yours.
- I created a test class with test data on Caché 2018.x and IRIS 2023.1FT and I have your query executed very quickly. Details below.
User.STSEARCHVISIT.cls
///
Class User.STSEARCHVISIT Extends %Persistent [ ClassType = persistent, DdlAllowed, Final, ProcedureBlock, SqlRowIdPrivate, SqlTableName = ST_SEARCH_VISIT ]
{
Property HQORGCODE As %Library.String(MAXLEN = 32) [ SqlColumnNumber = 2, SqlFieldName = HQ_ORG_CODE ];
Property HQORGNAME As %Library.String(MAXLEN = 32) [ SqlColumnNumber = 3, SqlFieldName = HQ_ORG_NAME ];
Property TENANTID As %Library.String(MAXLEN = 32) [ SqlColumnNumber = 4, SqlFieldName = TENANT_ID ];
Property GROUPPATIENTSN As %Library.String(MAXLEN = 32) [ SqlColumnNumber = 5, SqlFieldName = GROUP_PATIENT_SN ];
Property ORGPATIENTSN As %Library.String(MAXLEN = 32) [ SqlColumnNumber = 6, SqlFieldName = ORG_PATIENT_SN ];
Property NAME As %Library.String(MAXLEN = 64) [ SqlColumnNumber = 7 ];
Property SEXCODE As %Library.String(MAXLEN = 2) [ SqlColumnNumber = 8, SqlFieldName = SEX_CODE ];
Property SEXNAME As %Library.String(MAXLEN = 16) [ SqlColumnNumber = 9, SqlFieldName = SEX_NAME ];
Property BIRTHDATE As %Library.Date [ SqlColumnNumber = 10, SqlFieldName = BIRTH_DATE ];
Property MARRYCODE As %Library.String(MAXLEN = 2) [ SqlColumnNumber = 11, SqlFieldName = MARRY_CODE ];
Property MARRYNAME As %Library.String(MAXLEN = 16) [ SqlColumnNumber = 12, SqlFieldName = MARRY_NAME ];
Property IDENTIFYTYPECODE As %Library.String(MAXLEN = 5) [ SqlColumnNumber = 13, SqlFieldName = IDENTIFY_TYPE_CODE ];
Property IDENTIFYTYPENAME As %Library.String(MAXLEN = 32) [ SqlColumnNumber = 14, SqlFieldName = IDENTIFY_TYPE_NAME ];
Property IDENTIFYNUMBER As %Library.String(MAXLEN = 50) [ SqlColumnNumber = 15, SqlFieldName = IDENTIFY_NUMBER ];
Property BLOODTYPECODE As %Library.String(MAXLEN = 2) [ SqlColumnNumber = 16, SqlFieldName = BLOOD_TYPE_CODE ];
Property BLOODTYPENAME As %Library.String(MAXLEN = 12) [ SqlColumnNumber = 17, SqlFieldName = BLOOD_TYPE_NAME ];
Property MOBILE As %Library.String(MAXLEN = 50) [ SqlColumnNumber = 18 ];
Property MAILINGADDRESS As %Library.String(MAXLEN = 127) [ SqlColumnNumber = 19, SqlFieldName = MAILING_ADDRESS ];
Property VISITSERIALNO As %Library.String(MAXLEN = 64) [ SqlColumnNumber = 20, SqlFieldName = VISIT_SERIAL_NO ];
Property TABLEFLAG As %Library.String(MAXLEN = 1) [ SqlColumnNumber = 21, SqlFieldName = TABLE_FLAG ];
Property VISITTYPECODE As %Library.String(MAXLEN = 24) [ SqlColumnNumber = 22, SqlFieldName = VISIT_TYPE_CODE ];
Property VISITTYPENAME As %Library.String(MAXLEN = 64) [ SqlColumnNumber = 23, SqlFieldName = VISIT_TYPE_NAME ];
Property VISITDEPTCODE As %Library.String(MAXLEN = 32) [ SqlColumnNumber = 24, SqlFieldName = VISIT_DEPT_CODE ];
Property VISITDEPTNAME As %Library.String(MAXLEN = 64) [ SqlColumnNumber = 25, SqlFieldName = VISIT_DEPT_NAME ];
Property INOUTVISITNO As %Library.String(MAXLEN = 32) [ SqlColumnNumber = 26, SqlFieldName = IN_OUT_VISIT_NO ];
Property VISITTIME As %Library.PosixTime [ SqlColumnNumber = 27, SqlFieldName = VISIT_TIME ];
Property DISCHARGETIME As %Library.PosixTime [ SqlColumnNumber = 28, SqlFieldName = DISCHARGE_TIME ];
Property INHOSPITALTIME As %Library.PosixTime [ SqlColumnNumber = 29, SqlFieldName = IN_HOSPITAL_TIME ];
Property ICDCODE As %Library.String(MAXLEN = 20) [ SqlColumnNumber = 30, SqlFieldName = ICD_CODE ];
Property ICDNAME As %Library.String(MAXLEN = 64) [ SqlColumnNumber = 31, SqlFieldName = ICD_NAME ];
Property HEALTHCARDNO As %Library.String(MAXLEN = 32) [ SqlColumnNumber = 32, SqlFieldName = HEALTH_CARD_NO ];
Property HEALTHCARDTYPE As %Library.String(MAXLEN = 64) [ SqlColumnNumber = 33, SqlFieldName = HEALTH_CARD_TYPE ];
Property SURGCODE As %Library.String(MAXLEN = 20) [ SqlColumnNumber = 34, SqlFieldName = SURG_CODE ];
Property SURGNAME As %Library.String(MAXLEN = 64) [ SqlColumnNumber = 35, SqlFieldName = SURG_NAME ];
Property AGE As %Library.String(MAXLEN = 10) [ SqlColumnNumber = 36 ];
Property DISEASECODE As %Library.Integer(MAXVAL = 2147483647, MINVAL = -2147483648) [ SqlColumnNumber = 37, SqlFieldName = DISEASE_CODE ];
Property DISEASENAME As %Library.String(MAXLEN = 64) [ SqlColumnNumber = 38, SqlFieldName = DISEASE_NAME ];
Property LastChangedTime As %Library.PosixTime [ SqlColumnNumber = 39 ];
Property LastCreateTime As %Library.PosixTime [ SqlColumnNumber = 40 ];
Property GROUPORG As %Library.String(MAXLEN = 50) [ SqlColumnNumber = 41 ];
Parameter USEEXTENTSET = 0;
/// Bitmap Extent Index auto-generated by DDL CREATE TABLE statement. Do not edit the SqlName of this index.
Index DDLBEIndex [ Extent, SqlName = "%%DDLBEIndex", Type = bitmap ];
Index BITMAPINDEXSTSEARCHVISITBLOODTYPECODE On BLOODTYPECODE [ SqlName = BITMAP_INDEX_ST_SEARCH_VISIT_BLOOD_TYPE_CODE, Type = bitmap ];
Index BITMAPINDEXSTSEARCHVISITHQORGCODE On HQORGCODE [ SqlName = BITMAP_INDEX_ST_SEARCH_VISIT_HQ_ORG_CODE, Type = bitmap ];
Index BITMAPINDEXSTSEARCHVISITIDENTIFYTYPECODE On IDENTIFYTYPECODE [ SqlName = BITMAP_INDEX_ST_SEARCH_VISIT_IDENTIFY_TYPE_CODE, Type = bitmap ];
Index BITMAPINDEXSTSEARCHVISITMARRYCODE On MARRYCODE [ SqlName = BITMAP_INDEX_ST_SEARCH_VISIT_MARRY_CODE, Type = bitmap ];
Index BITMAPINDEXSTSEARCHVISITSEXCODE On SEXCODE [ SqlName = BITMAP_INDEX_ST_SEARCH_VISIT_SEX_CODE, Type = bitmap ];
Index BITMAPINDEXSTSEARCHVISITTABLEFLAG On TABLEFLAG [ SqlName = BITMAP_INDEX_ST_SEARCH_VISIT_TABLE_FLAG, Type = bitmap ];
Index BITMAPINDEXSTSEARCHVISITVISITDEPTCODE On VISITDEPTCODE [ SqlName = BITMAP_INDEX_ST_SEARCH_VISIT_VISIT_DEPT_CODE, Type = bitmap ];
Index BITMAPINDEXSTSEARCHVISITVISITTYPECODE On VISITTYPECODE [ SqlName = BITMAP_INDEX_ST_SEARCH_VISIT_VISIT_TYPE_CODE, Type = bitmap ];
Index INDEXSTSEARCHVISITBIRTHDATE On BIRTHDATE [ SqlName = INDEX_ST_SEARCH_VISIT_BIRTH_DATE, Type = index ];
Index INDEXSTSEARCHVISITDISCHARGETIME On DISCHARGETIME [ SqlName = INDEX_ST_SEARCH_VISIT_DISCHARGE_TIME, Type = index ];
Index INDEXSTSEARCHVISITGROUPPATIENTSN On GROUPPATIENTSN [ SqlName = INDEX_ST_SEARCH_VISIT_GROUP_PATIENT_SN, Type = index ];
Index INDEXSTSEARCHVISITIDENTIFYNUMBER On IDENTIFYNUMBER [ SqlName = INDEX_ST_SEARCH_VISIT_IDENTIFY_NUMBER, Type = index ];
Index INDEXSTSEARCHVISITINHOSPITALTIME On INHOSPITALTIME [ SqlName = INDEX_ST_SEARCH_VISIT_IN_HOSPITAL_TIME, Type = index ];
Index INDEXSTSEARCHVISITINOUTVISITNO On INOUTVISITNO [ SqlName = INDEX_ST_SEARCH_VISIT_IN_OUT_VISIT_NO, Type = index ];
Index INDEXSTSEARCHVISITMOBILE On MOBILE [ SqlName = INDEX_ST_SEARCH_VISIT_MOBILE, Type = index ];
Index INDEXSTSEARCHVISITNAME On NAME [ SqlName = INDEX_ST_SEARCH_VISIT_NAME, Type = index ];
Index INDEXSTSEARCHVISITORGPATIENTSN On ORGPATIENTSN [ SqlName = INDEX_ST_SEARCH_VISIT_ORG_PATIENT_SN, Type = index ];
Index INDEXSTSEARCHVISITVISITSERIALNO On VISITSERIALNO [ SqlName = INDEX_ST_SEARCH_VISIT_VISIT_SERIAL_NO, Type = index ];
Index INDEXSTSEARCHVISITVISITTIME On VISITTIME [ SqlName = INDEX_ST_SEARCH_VISIT_VISIT_TIME, Type = index ];
Index IdxMapOrg On HQORGCODE [ SqlName = IdxMapOrg, Type = index ];
Index LastChangedTimeIndex On LastChangedTime [ SqlName = LastChangedTimeIndex, Type = index ];
Index LastCreateTimeIndex On LastCreateTime [ SqlName = LastCreateTimeIndex, Type = index ];
Index idxGO On GROUPORG [ SqlName = idxGO, Type = index ];
Index INDEXPIPATIENTINFOHQORGCODE On (HQORGCODE, GROUPPATIENTSN) [ SqlName = INDEX_PI_PATIENT_INFO_HQ_ORG_CODE, Type = index ];
Index IdxGpsnorg On (GROUPPATIENTSN, HQORGCODE) [ SqlName = IdxGpsnorg, Type = index ];
Index IdxVisitorg On (VISITSERIALNO, HQORGCODE) [ SqlName = IdxVisitorg, Type = index ];
ClassMethod Fill(N = 50)
{
; bulk insert via SQL. This is convenient if USEEXTENTSET = 1
/*
d ..%KillExtent()
f i=1:1:N &sql(insert %NOLOCK %NOCHECK %NOINDEX %NOTRIGGER %NOJOURN into ST_SEARCH_VISIT(HQ_ORG_CODE,VISIT_SERIAL_NO)values(:i#4,:i#5))
*/
; bulk insert via globals
d DISABLE^%NOJRN
k ^User.STSEARCHVISITD,^User.STSEARCHVISITI
f i=1:1:N {
s $li(^User.STSEARCHVISITD(i),1)=i#4, ;HQ_ORG_CODE
$li(^User.STSEARCHVISITD(i),19)=i#5 ;VISIT_SERIAL_NO
}
s ^User.STSEARCHVISITD=N
d ENABLE^%NOJRN
w "insert - OK!",!
d ..%BuildIndices(,,,$$$NO)
w "BuildIndices - OK!",!
d $system.SQL.TuneTable("ST_SEARCH_VISIT",$$$YES)
d $system.OBJ.Compile($classname(),"cu-d")
w "OK",!
}
}Generating 6000000 records
USER>d ##class(User.STSEARCHVISIT).Fill(6e6) OK
explain select count(distinct by(VISIT_SERIAL_NO,HQ_ORG_CODE) 1) from ST_SEARCH_VISIT
<plans>
<plan>
<sql>
select count(distinct by(VISIT_SERIAL_NO,HQ_ORG_CODE) 1) from ST_SEARCH_VISIT /*#OPTIONS {"DynamicSQL":1} */
</sql>
<cost value="29794316"/>
Call module B. Output the row.
<module name="B" top="1">
Read index map ST_SEARCH_VISIT.IdxVisitorg, looping on %SQLUPPER(VISIT_SERIAL_NO), %SQLUPPER(HQ_ORG_CODE), and ID. For each row: Check distinct values for %SQLUPPER(HQ_ORG_CODE) and %SQLUPPER(VISIT_SERIAL_NO) using a temp-file. For each distinct row: Accumulate the count([value]).
</module>
</plan>
</plans>select count(distinct by(VISIT_SERIAL_NO,HQ_ORG_CODE) 1) from ST_SEARCH_VISIT
Row count: 1 Performance: 2.8704 seconds 6003078 global references 36016391 lines executed
explain select count(1) from (select distinct by (VISIT_SERIAL_NO,HQ_ORG_CODE) VISIT_SERIAL_NO,HQ_ORG_CODE from ST_SEARCH_VISIT)
<plans>
<plan>
<sql>
select count(1) from (select distinct by (VISIT_SERIAL_NO,HQ_ORG_CODE) VISIT_SERIAL_NO,HQ_ORG_CODE from ST_SEARCH_VISIT) /*#OPTIONS {"DynamicSQL":1} */
</sql>
<cost value="21000"/>
Call module B. Output the row.
<module name="B" top="1">
Read index map ST_SEARCH_VISIT.IdxVisitorg, looping on %SQLUPPER(VISIT_SERIAL_NO) and %SQLUPPER(HQ_ORG_CODE). For each row: Call module I. Accumulate the count([value]).
</module>
<module name="I" top="1">
Read index map ST_SEARCH_VISIT.IdxVisitorg, using the given %SQLUPPER(VISIT_SERIAL_NO) and %SQLUPPER(HQ_ORG_CODE), and looping on ID. For each row: Accumulate the [value].
</module>
</plan>
</plans>select count(1) from (select distinct by (VISIT_SERIAL_NO,HQ_ORG_CODE) VISIT_SERIAL_NO,HQ_ORG_CODE from ST_SEARCH_VISIT)
Row count: 1 Performance: 0.0269 seconds 3079 global references 17711 lines executed
- Log in to post comments
