Hi, We are currently migrating our Pick based system to Cache and one of the main reasons is to speed up the processing time. The system is basically an accommodation enquiry system and when overloaded by users the processing time is considerably downgraded. Any tips on amending programs to suit the Cache enviroment would be much appreciated. Thanks
--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en
Chris,
As Dave indicated some the responses will depend on where you are coming from. If you are coming from D3 then case sensitivity becomes a issue due to D3 being case insensitive . If you are coming from Universe or Unidata then this will not be a problem as both those environments are case sensitive also.
One other thing that Dave had mentioned has been dealt with. For practical purpose we no longer have a limit on routine (program) size. While on the topic of program one thing you will notice is that our compiler is tighter than many others in the MV world. Some examples:
· Spaces in line label definitions; HANDLE.LINE : is on legal due to the space before the:
· Reserve word conflicts
· Missing concatenation operators; LINE = SomeData “ additional text added to the end”. The quoted text get interpreted as a formatting option due to the : missing between SomeData and the quote
For further feedback I need to understand if you are referring to issues that may come up in migration or if you are looking for ways to get better performance out of Caché. Let me take a brief shot at both
Issues beyond the syntax items show above:
· Reading large blocks of text into memory. I have run into cases where, rather than using READSEQ to read in a large text file, the record is put into directory type file and input using READ. The issue here is that Caché has a 3.6 million character limit on strings. You can handle this in two ways. If you want to stick with purely MV Basic commands you can do READSEQ to handle the file line-by-line. A better way would be to use our File Stream handling API. The program would still be written in MV Basic, you would just use our API in place of MV Basic statements.
· Socket handling uses our standard Sockets API
· HTTP handling uses our standard API
· Web Services would need to be implemented using our methodology, which is very easy by the way. You could still just call an existing MV Basic subroutine from the web service.
Performance
· Caché adds some new in-memory structures that can be used in place of Dynamic arrays. I have used both these techniques in MV Basic programs to achieve vast improvements in performance.
o Cache Arrays – these are arrays that can be indexed by any string value. For example it is a common technique to build a dynamic array with two VM separated attributes. The first contains a code and the next a value related to that code. When you need that value you do a locate on the first attribute to find the position of the value in the second attribute. With a Caché array you can make the index of the array the code. So instead of doing and locate on CODE you would do: VALUE = LOOKUPARRAY(CODE).
o There are also listing structures, called $LISTs, that are binary in nature and extremely fast
· Use our Class API’s. There are many cases where we have an API to handle a particular function that performs better. This can be due to simplifying code or just due to that function be highly optimized. A great example is email. In Cache we handling this completely within an API rather than having to call out to OS level functions.
We can help out more as specific issues come up. One of the greatest advantages InterSystems and Caché brings to the MV World is options and support. You have already found this Community forum and I would continue to use it. Post here any time you have something that you need to deal with. Of course your Sales Engineer is a great resource for these issues. Finally, our support group is world class.
Richard S Taylor
Sales Engineer
InterSystems Corporation
Office: 443-340-8614
FAX: 440-815-5805
![]()
--
<image001.jpg>
From: intersy...@googlegroups.com [mailto:intersy...@googlegroups.com] On Behalf Of ChrisB
Sent: Tuesday, September 11, 2012 10:38 AM
To: InterSy...@googlegroups.com
Subject: [InterSystems-MV] Help in migrating to Cache from Pick
Hi, We are currently migrating our Pick based system to Cache and one of the main reasons is to speed up the processing time. The system is basically an accommodation enquiry system and when overloaded by users the processing time is considerably downgraded. Any tips on amending programs to suit the Cache enviroment would be much appreciated. Thanks
--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en
--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en
--
"He is your friend, your partner, your defender, your dog. You are his life, his love, his leader. He will be yours, faithful and true, to the last beat of his heart. You owe it to him to be worthy of such devotion" -- Unknown
--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en
Hi Dave,
Many thanks for your response.
Although we use both D3 and MVbase all our development has been carried out in MVbase so we do not have the problem with Cache being case sensitive. So far we have reached steps 1 & 2 with little difficulty and any new developments will be carried out using the Cache specific tools though we do not wish to amend out current suite of programs too much. I am really after any tips on how to improve performance on this current suite such as using globals rather than the traditional open/read/write Pick commands and also ways of dealing with dynamic arrays etc.
Chris
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en checked for viruses and spam by CanIt.
http://www.canit.3d.net.uk/
--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en
Rich
First of all thanks for all your info . We have nearly converted all our software to be compatible with Cache and are now looking at ways of increasing performance. The concept of cache arrays looks interesting as we use dynamic arrays extensively in conjunction with commands such as LOCATE, INSERT etc but not sure how to use these cache arrays as you have suggested.
Thx
Chris
checked for viruses and spam by CanIt.
http://www.canit.3d.net.uk/
--
Chris,
I would avoid writing straight to globals in your MV code. Doing so avoids any triggers you might have on your writes. We do use globals every once in a while to read data quickly (avoiding an open on the file). When doing this, make sure you look at the MD for the global name. While Cache does name globals after your files most of the time sometimes the global associated with your MV file might be named something like ^D3 or some such thing.
One trick we use is to put information to pass between programs in process private globals. They come in the form of ^||GlobalName. The benefit of using them is that they are only available to the process they are written in and are cleaned up once that process dies. We find them particularly useful in our green screen programs. Our system uses a PROC based menu to launch MV programs. In try/catch blocks, we put information into a specific process private global. When the program hits the PROC again, we check that global and if it has information, we pass it to a crash handler that asks the user for information about the crash. We then email the stack traces, code snippets and user information from the error. This has allowed us to clean up our code because we now have an automated process for handling errors (rather than relying on users to call us).
That is another thing that helped us a ton. Use Cache's exception handling. It is really good and allows for some powerful error handling on your end. You can even derive from Cache's exception base class to create your own exceptions.
We have been moving our code more towards objects instead of MV files because that is where the true power of Cache in MV lies. Getting MV projections along-side SQL and .Net access is huge in terms of productivity for us. Also, some things in Cache ONLY work in objects and sometimes only with COS code (&html<>, &sql<> and $$$ macros are some that come off the top of my head).
We were some of the early adopters for MV in Cache, so I can't remember what issues we ran into. However, if you have some specific questions, the members on this board are very friendly and will be able to help. One thing I do remember is that Cache was extremely helpful during our conversion. Their support was actually one of the most important factors in us going with Cache.
Jason
On Wednesday, September 12, 2012 1:30:17 PM, chrisb wrote:
Hi Dave,
Many thanks for your response.
Although we use both D3 and MVbase all our development has been
carried out in MVbase so we do not have the problem with Cache being
case sensitive. So far we have reached steps 1 & 2 with little
difficulty and any new developments will be carried out using the
Cache specific tools though we do not wish to amend out current suite
of programs too much. I am really after any tips on how to improve
performance on this current suite such as using globals rather than
the traditional open/read/write Pick commands and also ways of dealing
with dynamic arrays etc.
Chris
*From:*intersystems-mv@googlegroups.com
[mailto:intersystems-mv@googlegroups.com] *On Behalf Of *Dave
*Sent:* 11 September 2012 16:04
<mailto:CacheMV@googlegroups.com>
To unsubscribe from this group, send email to
For more options, visit this group at
http://groups.google.com/group/CacheMV?hl=en
--
You received this message because you are subscribed to the Google
Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
<mailto:CacheMV@googlegroups.com>
To unsubscribe from this group, send email to
For more options, visit this group at
http://groups.google.com/group/CacheMV?hl=en checked for viruses and
spam by CanIt.
http://www.canit.3d.net.uk/
--
You received this message because you are subscribed to the Google
Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to
For more options, visit this group at
http://groups.google.com/group/CacheMV?hl=en
--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-unsubscribe@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en
MV is limited to 3 dimensions with AM/VM/SVM. When dealing with XML, JSON, exploded bill of materials, complex multi-tier business relationships, nested objects, and other n-tier tree structures, there are plenty of opportunities to go way beyond that. In the MV world people tend to reformat data and convince themselves that 2 or 3 dimensions are plenty good for any task, but the reality is that we are still spending time to reorganize data to accommodate limitations in the model. Even if re-writing code into Caché classes, or using the fine set of %functions that are available, ultimately n-dimensional constructs get serialized to MV limitations just to get the data to fit into the traditional file structures.
The Caché global gives us an opportunity to think outside of the traditional MV box once we've transitioned away from it. I think this feature is under-marketed to a market where everyone has already bought into the concept of multi-dimensional data. It's been a while since I've spent serious time in Caché but I don't think the full power of Caché globals has been made available "elegantly" to MV. So it seems there is more there than most people know, and less there than what could be. That seems to me like a recipe for great things to happen in terms of marketing, sales, and engineering.
--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en
HL7 is basic EDI which people have been doing with MV for years. This is another case of "just port it first and optimise later". But I'd think that there would be a Caché HL7 Working Group somewhere, with COS developers focused on best practices for parsing and building huge HL7 docs. Given the benefits of classes, I'd think that there should be a "standard" class out there which parses docs into nested objects. Parsing HL7 should be as easy as calling a lower-level %XML function - except that this would be a higher-level wrapper class. The next step would be to pass the parsed data to MVBASIC for application-specific logic. But in this scenario there's that "impedance mismatch" between objects and MVBASIC. It might be much more convenient to save a visit or lab result object (accessions, etc) as-is rather than breaking that up into pieces that MV can digest. But like Ed said, in order for queries to work we can't do that. Sure, MV logic would have to be re-written to handle this anyway. What I'm suggesting is that for new code written by someone coming to Caché from MV, or to MV from Caché, there really shouldn't be this broad gap between the environments. Again as Ed suggests, classes and objects might be the answer to all of this, but (and remember I'm rusty here so I'll qualify with "I believe") within the class code we still need to break down data elements for MV structures and then re-hydrate them on the way out. That tier of effort for the developer and system resources should not exist.
Fun discussion, thanks.
T
--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en
Ensemble is the tool to use if you are heavily into messaging (HL7, X12, EDIFACT,..) or integration. Ensemble is Caché plus so you have all the power of Caché.
As to MV structures and classes, if I understand you correctly Tony, you do not need to do any handling of the MV structure from the class. You simply extend from %MV.Adaptor the adaptor will take care of mapping properties to attributes and such.
--
Chris,
Let me start with some basics on Globals. All subscripts in a Globals are automatically in Ascending order. For example if I create a global with three entries “B”, “C”, and “A” they are actually held in the global in alpha order not the order they were entered. So in this example the global, let’s say it was called RST, would look like this if dumped:
RST("A")="letter a"
RST("B")="letter b"
RST("C")="letter c"
You can see that the subscript of the array is not limited to being numeric and it is in order. This can often eliminate the need to locate and insert that would be necessary in a dynamic array. For code tables this becomes even more beneficial. For example take the sample MV code below.
CodeTable<1,-1> = “AB” ; * code
CodeTable<2,-1> = “123” ;* factor
CodeTable<1,-1> = “CD”
CodeTable<2,-1> = “234”
CodeTable<1,-1> = “DE”
CodeTable<2,-1> = “54”
ProcessCode = “CD”
Locate(ProcessCode,CodeTable,1;idx) then
ProcessFactor = CodeTable<2,idx>
End else
ProcessFactor = 0
End
The code table could have been loaded from a table or other source.
Using a Cache Array would look like this
DIM CodeTable() ; * note the empty dimensions. This tells the compiler to use a Cache Array
CodeTable(“AB”) = “123”
CodeTable(“CD”) = “234”
CodeTable(“DE”) = “54”
ProcessCode = “CD”
ProcessFactor = $Get(CodeTable(ProcessCode)) ; * the $get() function protects against undefined array positions replacing the else clause of the locate.
This syntax allows for cleaner code and much faster execution particularly if this lookup is done often on large arrays.
Another example is building list of invoices that are to be in order then later updating a Dynamic array. Doing a locate and insert at each invoice would not perform well for large arrays Instead do this:
Dim InvoiceList()
loop while readnext InvoiceNo do
* Process the invoice
* at the end add the invoice to the list
InvoiceList(InvoiceNo) = “” ; * the value of the array is meaningless in this example
Repeat
* now update a MV record with the list of invoices
* $order iterates through a Caché array returning each new subscript until it runs out. At that point the variable is set to the empty string.
InvoiceNo = “”
InvoiceArray = “”
Loop
InvoiceNo = $order(InvoiceList,InvoiceNo)
Until InvoiceNo = “” do
InvoiceArray<1,-1>
repeat
MyRecord<some attribute> = InvoiceArray
I have use both these techniques to get performance improvements from 33% to insane levels. The later technique took a 5 hour process down to 2 minutes. I expect that this was a isolated “Perfect Storm” of benefits, but it is fun to talk about J
I didn’t mean the MV syntax was isolated, just the ability to gain that vast of an improvement. I think that gain had a lot to do with the process and environment rather than the syntaxes involved. I can still get some big improvements with these techniques.
On $LISTs, Yes these are another technique for speeding things up. I have used that also. You also have some need functions like LISTFROMSTRING and LISTTOSTRING that can convert delimited string into a list.
From: intersy...@googlegroups.com [mailto:intersy...@googlegroups.com] On Behalf Of James Westley Farrell
Sent: Friday, September 14, 2012 4:43 PM
To: intersy...@googlegroups.com
A Quick suggestion would be to build your array as:
Hotels(price,HotelID) = $list of hotel information.
This would put the information first in Ascending price order then within price by Hotel. Using the $order function you can traverse this array in either forwards or backwards directions so you can get the effect of changing the sort from ascending to descending without having to rebuild the array. Also note that $ order works on on subscript of the array. So the fully traverse the array by price then show all the hotels will require nested loops using $ order on the different subscript levels.
You could store the data in a global or even a local array, in a simple form:
Set id=$i(^data),^data(id)=hotelinfo ; something maybe like: $lb("Hilton",300,"Smoking","King","WiFi")
And then make an index:
Set ^priceindex(price,id)=""
You can then use $order to find the hotels, in ascending or descending order, or even find a range, very quickly.
This approach also eliminates the problem of having multiple hotels with rooms for the same price.
That's the beauty of Caché local and global arrays.
Scott JonesChris,
I will both agree and disagree with Ed on some points. In my experience doing direct global reference is great when you want to get the absolute best performance on read only access of data. I would almost NEVER use this to update production records. This is due to many of the reasons Ed stated; locking, triggers, indexes and such.
I know that your goals are to increase processing speed. What I have found is that reading directly from globals can provide a boost, but what really kicks things up is to look at the in memory structures that you may build in your processes. I would look for places where you do locate/insert and locate/access or similar syntaxes. Replacing this with Caché arrays can provide some significant performance improvements. This is because you can key the Caché array by the index value that you were previously would have had to locate on. The reference now becomes much more direct.
As Ed stated, if it isn’t broke I would not ‘fix’ it.
To that end you probably want to look at some of your bigger processes and do a code profile to see where the time is being taken before making wholesale changes. This tool is %SYS.MONLBL in Caché. You can search the documentation for this. Just be aware that the ‘routine’ that being profiled is not necessarily called the same thing. You need to look at line two of the cataloged VOC entry to see the internal routine name that is used by Caché. This is the code you will actually profile. If you need any help running this let us know.
Richard S Taylor
Sales Engineer
InterSystems Corporation
Office: 443-340-8614
FAX: 440-815-5805
Sent: Thursday, October 04, 2012 9:51 AM
To: InterSy...@googlegroups.com
--
Well, not sure about Caché arrays, but you can do this with lists. You can use the $LISTFROMSTRING() and $LISTTOSTRING() functions.
From: intersy...@googlegroups.com [mailto:intersy...@googlegroups.com] On Behalf Of James Westley Farrell
Sent: Friday, October 05, 2012 9:16 AM
To: intersy...@googlegroups.com
Rich & Ed,Thanks for your prompt response to my query and for the help and advice. I have used the CPG’s now with the $ORDER function which has been a great help in speeding up the sorting of data (primarily by price either ascending or descending). The only remaining area which slows the processing speed is when the system tries to ascertain a price for a hotel. The price data is held as such;1> 16355]16359]16362]16366]16372]16375]16389]16391] etc etc these are the date fields2> 4500]4200]4100]4500]4200]4100]4400]4600]4300] etc - these are the prices for the datesIf an enquiry is for eg 10nights, the system has to go through each date band and ascertain the price accordingly, so for example it could be 3 nights at 45.00, 2 nights at 42.00, 5 nights at 41.00 . The dat es can stretch over a whole year and can contain quite a large array. To obtain the price I first locate the arrival date in attr<1> and then do a for /next loop until the end date (start date + 10 nights) has been passed and then total up the prices. It is this subroutine that calculates the price that is the most time consuming. Apart from that working with Globals has been really useful though not always sure how to make the most of Cache’s utilities as they do not always seem to be documented or am I missing something?
Hi Chris,
I meant to send this last week, but it became a lost draft…
Reading a global returns the same result as a READ: a dynamic array delimited by marks chars.
If your sub XXXXXX does little with the array and you don’t mind changing code from:
PRCTAB(1)
to:
PRCTAB<1>
then the following would work:
PRCKEY='000001'
IF $D(^PRICES(PRCKEY)) THEN PRCTAB=^PRICES(PRCKEY); GOSUB XXXXXX ELSE ERRMSG='XXXXXXXXXX'
Notes:
1. $D checks for the existence of the item
2. I don’t know whether it is a bug or expected, but if I change your line 2 to:
MAT PRCTAB=”M”
the MATREAD resets unused values to empty, removing my “M”
3. could use MATPARSE to convert
From: intersy...@googlegroups.com [mailto:intersy...@googlegroups.com]
On Behalf Of ChrisB
Sent: Thursday, October 04, 2012 9:50 AM
To: InterSy...@googlegroups.com
Subject: [InterSystems-MV] Re: Help in migrating to Cache from Pick
Hi, Further to our migration from Pick to Cache, can anyone tell me how to code the following in Pick code using cache globals, ie using ^PRICES and ^PRCTAB etc without the OPEN/READ commands etc,
--