Oprettet ons. d. 14. januar 2009 kl. 02:05:34

buzzzz
buzzzz (46.581 point. Point ude: 180)
ifyoudo.net

Compare på 2 string giver forkert resultat.

Hej,

http://syska.dk/ (...)

Kloge råd er dyre ... kig på overstående billede.

Ved debug kan jeg se at mine 2 stringe er ens.

Når jeg udskriver deres værdi, char for char, er de også ens.

Hvad går der galt ? Hvad har jeg overset ?

Ene string kommer fra en tekst fil ...
StreamReader sr = new StreamReader(MapPath + "\\" + FileName, System.Text.Encoding.UTF8)

Andet kommer fra en database ...

Collation i databasen er Danish_Norwegian_CI_AS

HELP, totally lost here ... noget jeg har overset ?

Skrevet ons. d. 14. januar 2009 kl. 02:24:15| #1

lasserasch
lasserasch (9.747 point)
www.r-coding.dk
Jeg er lige med på en lytter....

Skrevet ons. d. 14. januar 2009 kl. 02:36:53| #2

arne_v
arne_v (1.005.658 point)
øh

så vidt jeg kan se er logikken:

if(new != current) {
  current = new
  // dump current
  // dump new
}

du skal nok dump inden du sætter current lig med new.

Skrevet ons. d. 14. januar 2009 kl. 03:02:12| #3

buzzzz
buzzzz (46.581 point)
ifyoudo.net
haha ... okay, første dumme fejl ...

Men det har så noget med encoding at gøre ... nu er der nemlig forskel :-p

men ... så må det jo være noget med at jeg skal convert en af mine stringe til UTF8 eller ? Hvad ligger data gemt som i en MSSQL 2008 DB ? Bliver hentet ind med LINQ to SQL datacontext.

Skrevet ons. d. 14. januar 2009 kl. 03:29:57| #4

arne_v
arne_v (1.005.658 point)
Strings i memory er altid Unicode UTF-16.

Så i givet fald er det indlæsningen fra fil og DB den er gal med.

Hvilke char værdier har fil og DB ?

Er filen i UTF-8 ?

Er feltet en VARCHAR eller en NVARCHAR ?

Skrevet ons. d. 14. januar 2009 kl. 03:35:10| #5

buzzzz
buzzzz (46.581 point)
ifyoudo.net
http://syska.dk/ (...) - Der char værdierne

Filen er UTF-8 ... har jeg set via headers hvor den bliver hentet fra.
http://s4.travian.dk/ (...)

DB er et varchar(50) felt.

Skrevet ons. d. 14. januar 2009 kl. 04:02:59| #6

buzzzz
buzzzz (46.581 point)
ifyoudo.net
hehe, den postede selvom exp.dk er nede til vedligeholdelse ... utroligt de ikke kan få lavet sitet så det ikke skal være nede :-s tsk tsk.

Men jeg vil daffe i seng og håber på godt svar i morgen når jeg står op :-p

Sådan et lille problem kan give sådan et besvær :-(

Skrevet ons. d. 14. januar 2009 kl. 04:18:07| #7

arne_v
arne_v (1.005.658 point)
Hvis du skal have tegn >255 så er NVARCHAR nok en god ide !!

Skrevet ons. d. 14. januar 2009 kl. 04:19:39| #8

buzzzz
buzzzz (46.581 point)
ifyoudo.net
dvs ... du siger at mit problem bliver løst hvis jeg bruger nvarchar ?

men når det blvier printet ud ser det jo rigtigt ud ... nu er er der nogen der ikke hænger sammen mere i min hjerne.

Skrevet ons. d. 14. januar 2009 kl. 14:52:03| #9

arne_v
arne_v (1.005.658 point)
Jeg vil ikke garantere det.

Men VARCHAR er beregnet til tegn 0-255 og NVARCHAR er beregnet til tegn 0-65535.

Du har tegn over 255.

Det er ihvertfald vaerd at forsoege med NVARCHAR.

Skrevet ons. d. 14. januar 2009 kl. 21:09:12| #10

buzzzz
buzzzz (46.581 point)
ifyoudo.net
No ... still the same ... men så må jeg jo bare convertere mit UTF8 til Unicode, men der er noget som går galt.

Taget fra MSDN ... men der går noget galt ... Unicode er 4 byte, UTF8 er 2 ....

private string ConvertUTF8ToUnicode(string input)
        {
            // Convert the string into a byte[].
            byte[] utf8Bytes = unicode.GetBytes(input);

            // Perform the conversion from one encoding to the other.
            byte[] unicodeBytes = Encoding.Convert(utf8, unicode, utf8Bytes);

            // Convert the new byte[] into a char[] and then into a string.
            // This is a slightly different approach to converting to illustrate
            // the use of GetCharCount/GetChars.
            char[] unicodeChars = new char[unicode.GetCharCount(unicodeBytes)];
            unicode.GetChars(unicodeBytes, 0, unicodeBytes.Length, unicodeChars, 0);
            string unicodeString = new string(unicodeChars);

            return unicodeString;
        }

Skrevet ons. d. 14. januar 2009 kl. 21:13:46| #11

arne_v
arne_v (1.005.658 point)
Unicode er strenget taget ikke bytes, men naar man siger unicode mener man normalt 2 bytes
per tegn. UTF-8 er et variabel antal bytes per tegn - typisk 1 eller 2 paa vores laengdegrader.

Og jeg tror slet ikke paa konverterings loesningen. Du skal finde ud af hvor det gaar
galt i data.

Skrevet ons. d. 14. januar 2009 kl. 21:16:03| #12

buzzzz
buzzzz (46.581 point)
ifyoudo.net
Ups ... i toppen der var en fejl ...

unicode.GetBytes skal selvf være utf8.GetBytes

http://syska.dk/ (...)

Men nu går det da helt galt ... nu bliver mit navn ... i dette tilfælde gemt som et "a" og ikke dette mærkelige "a" som du kan se på billedet.

// ouT

Skrevet ons. d. 14. januar 2009 kl. 21:22:42| #13

buzzzz
buzzzz (46.581 point)
ifyoudo.net
Hvad er det Collation præcis ?

http://help.travian.dk/ (...) under "Hvilket format har dataene?"

UTF8 ... og der er faktisk ingen spille verdener 2 tilbage ...

Så jeg går ud fra at jeg skal lede efter fejler på min SQL 2008 server.

Skrevet ons. d. 14. januar 2009 kl. 21:29:14| #14

arne_v
arne_v (1.005.658 point)
collation er "sorterings raekkefoelge"

Skrevet ons. d. 14. januar 2009 kl. 21:49:03| #15

buzzzz
buzzzz (46.581 point)
ifyoudo.net
En simple test inde fra SSMS:
table med ID og Name:
CREATE TABLE [dbo].[TestLort](
    [TestID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL
) ON [PRIMARY]

INSERT INTO TestLort ([Name]) VALUES ('.α');
SELECT * FROM TestLort WHERE Name = '.a'

Min select kan finde overstående ... WHY :-s

Skrevet ons. d. 14. januar 2009 kl. 21:49:39| #16

buzzzz
buzzzz (46.581 point)
ifyoudo.net
Ja okay ... Eksperten gør så et eller andet ved mit bogstav, men det er "alpha" mener jeg.

// ouT

Skrevet ons. d. 14. januar 2009 kl. 22:03:16| #17

buzzzz
buzzzz (46.581 point)
ifyoudo.net
Okay ... måske fundet en lille fejl i mit system som skal rettes først.

Hvordan kan jeg dynamisk lave min stringe om så min server forstår det ?

Før brugte jeg LINQ til at lave det ... og der kom det rigtigt ind. Så imens har de 2 ting her næsten kommet frem, da jeg havde undersøgt andre måder at lave mine updates af de navne på ...

ved at bruge MERGE INTO ... hviket gav en speed up på en factor 12. great, men intet er så godt at det ikke kommer uden problemer ... så hvordan skal jeg få de special tegn med over ?

Det skal ligesom løses først kan jeg regne ud :-p.

Min query kommer til at se ca. sådan her ud:
MERGE INTO Villages AS V
USING (Values
(7,34,34,'.α',1)
) I([SID], [VID], [UID], [Name], [Active])
ON (V.[SID] = I.[SID] AND V.[VID] = I.[VID])
WHEN MATCHED THEN
UPDATE SET [UID] = I.[UID], [Name] = I.[Name], [Active] = I.[Active];

Men ... undervejs bliver mit alpla tegn åbenbart lavet om :-s

I'm lost here.

Skrevet ons. d. 14. januar 2009 kl. 22:10:49| #18

buzzzz
buzzzz (46.581 point)
ifyoudo.net
Nu er det et import som jeg kun selv har adgang til ... men normalt sørger sqlparameters jo for at beskytte mod sql injection ...  men hvad gør man sådan manuelt selv ?

Der er jo ligepludselig en del problemer man skal tage stilling til ... :-(

btw, der skal nok komme lidt ekstra point på :-)

Skrevet ons. d. 14. januar 2009 kl. 22:12:28| #19

arne_v
arne_v (1.005.658 point)
Jeg kan proeve at teste lidt selv naar jeg kommer hjem fra arbejde.

Skrevet ons. d. 14. januar 2009 kl. 22:53:03| #20

buzzzz
buzzzz (46.581 point)
ifyoudo.net
ahhh

UPDATE t1 SET Name = N'test' WHERE ID = 10 :-)

og ja, det var vist det nvarchar og en utrolig omgang ... stirre sig blind på det.

smid svar.

Skrevet ons. d. 14. januar 2009 kl. 22:59:10| #21

websmith
websmith (22.187 point)
Har du konverteret din kolonne til nvarchar? Hvis ikke så vil dine "special" tegn ihvertfald ikke fungere.

Din "TestLort" tabel bruger jo nvarchar, som er unicode og varchar bruger så vidt jeg husker ANSI codepagen fra windows, hvilket måske ikke har de karakterer du ønsker.

Den fil du importerer fra, har du prøvet som test at skrive den til en anden fil igen, og sammenligne om du får skrevet det korrekt der - hvis det ikke er tilfældet, så kan det skyldes encoding af filen som er forkert.

En alternativ grund til at den ikke finder noget er at SQL serveren fortolker dit alpha tegn som et a. Dette kan skylde Collation kombineret med en varchar.

Jeg ville teste med en NVARCHAR kolonne i en tabel som bruger SQL_Latin1_General_CP1_CI_AS som collation. Det er ihvertfald altid den collation jeg bruger og jeg har ikke haft de problemer du angiver.

Hvad er det egenligt du prøver at løse med den MERGE syntax i din SQL?

Skrevet ons. d. 14. januar 2009 kl. 22:59:49| #22

websmith
websmith (22.187 point)
hmm, godt du selv fandt ud af det imens jeg skrev :)

Skrevet tor. d. 15. januar 2009 kl. 01:09:10| #23


Skrevet tor. d. 15. januar 2009 kl. 14:23:29| #24

buzzzz
buzzzz (46.581 point)
ifyoudo.net
Hej,

Websmith:
Jeg løset et UPDATE af mange rows på en smart måde ... jeg har i hvert fald ikke kunne finde andre og bedre alternativer end det. Så hvis du har en hvorpå jeg kan update 30.000 rows hurtigt, så kører jeg gerne.

Arne:
Men ... jeg må sige at de guide lines som travian selv har skrevet, nok fra start har kastet mig i den forkerte retning ... DAMM them to hell. Men så længe det er løst er jeg glad ... det får vi i hvert fald at se senere i dag :-). Der skulle helst ikke være så mange navne på de russiske og kinesiske server som har ændret navn.

Insert bliver lavet med SqlBulkCopy ... super hurtig.

But still ... det hele hænger lidt i svinget med Update ... :-(

// ouT

Skrevet fre. d. 16. januar 2009 kl. 00:30:15| #25

arne_v
arne_v (1.005.658 point)
UPDATE bør ikke være så slem med relevante index på tabellen. Og hvis du vil give en hjælpende
hånd til SQLServer, så bundter du en masse updates i en enkelt transaktion.

Skrevet fre. d. 16. januar 2009 kl. 03:37:45| #26

buzzzz
buzzzz (46.581 point)
ifyoudo.net
Ikke destro mindre skal jeg have lavet omkring 6 mill af dem ... når jeg får tilføjet de sidste servere hvor der også skal hentes data fra ...

Pt tager det ca. 48 mins at sammenligne mine data hvoraf netop det meste af tiden bliver brugt på UPDATE af forskellige ting. Tror jeg sparede 40% af tiden ved at lave updates på den her måde, så det synes jeg var et godt hop i den rigtige retning.

Men du siger det kan gøres hurtigere ... så tester jeg gerne. Men for ikke at jeg laver nogen mærkelige ting, så vil det være fedt med et eksempel på hvordan det kan gøres. Start til slut, da jeg synes jeg har været alt igennem. Det sidste jeg har lavet har klart gjort den største forskel.

Jeg har nogen klasser hvor mine data bliver indlæst og sammenlignet ... og det registere jeg så ... og kan deraf oprette mine quries som det skal være ... for at optimere det hele. Sådan det kun er ændret data jeg updatere, og nyt data bliver så indsat.

Der er rigtige indexes på ... slår op via 2 columns som sammen er PK. Første er ServerID og andet er det unikke id på netop den server.

Går ud fra at det er fint nok at bruge ens PK, den er jo også et index.

Det må vist være alt for denne gang.

Skrevet lør. d. 17. januar 2009 kl. 20:23:59| #27

buzzzz
buzzzz (46.581 point)
ifyoudo.net
mere input til sidste post ?

Skrevet lør. d. 17. januar 2009 kl. 20:31:31| #28

arne_v
arne_v (1.005.658 point)
Det er ikke særligt klart for mig hvad du præcist gør.

Har du prøvet at bundte mange updates i en enkelt transaktion ?

Skrevet lør. d. 17. januar 2009 kl. 20:56:04| #29

buzzzz
buzzzz (46.581 point)
ifyoudo.net
Som sagt ... har prøvet det meste af hvad jeg kender til ... og eneste som giver et bedre resultat er MERGE.

Men ... da jeg intet præcist eksemple har for hvad du præcist vil have mig til at prøve, går jeg ud fra det skulle være noget ala ( taget fra MSDN ):
public void RunSqlTransaction(string myConnString)
{
    SqlConnection myConnection = new SqlConnection(myConnString);
    myConnection.Open();

    SqlCommand myCommand = myConnection.CreateCommand();
    SqlTransaction myTrans;

    // Start a local transaction
    myTrans = myConnection.BeginTransaction();
    // Must assign both transaction object and connection
    // to Command object for a pending local transaction
    myCommand.Connection = myConnection;
    myCommand.Transaction = myTrans;

    try
    {
      myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'Description')";
      myCommand.ExecuteNonQuery();
      myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'Description')";
      myCommand.ExecuteNonQuery();
      myTrans.Commit();
      Console.WriteLine("Both records are written to database.");
    }
    catch(Exception e)
    {
      try
      {
        myTrans.Rollback();
      }
      catch (SqlException ex)
      {
        if (myTrans.Connection != null)
        {
          Console.WriteLine("An exception of type " + ex.GetType() +
                            " was encountered while attempting to roll back the transaction.");
        }
      }
   
      Console.WriteLine("An exception of type " + e.GetType() +
                        " was encountered while inserting the data.");
      Console.WriteLine("Neither record was written to database.");
    }
    finally
    {
      myConnection.Close();
    }
}

og så sætte min CommandText til:
UPDATE t1 SET Pop = 10 WHERE SID = 7 AND VID = 20;
UPDATE t1 SET Pop = 10 WHERE SID = 7 AND VID = 20;
UPDATE t1 SET Pop = 10 WHERE SID = 7 AND VID = 20;

Og så bundle dem 1000 stk sammen ... er dette korrekt forstået ?

Skrevet lør. d. 17. januar 2009 kl. 21:46:05| #30

arne_v
arne_v (1.005.658 point)
BeginTransaction
1000 x ExecuteNonQuery
Commit

nogle gange giver det en ganske pæn performance forbedring

Skrevet lør. d. 17. januar 2009 kl. 21:54:21| #31

buzzzz
buzzzz (46.581 point)
ifyoudo.net
Jamen ... så vil jeg da prøve overstående, dog med den lille rettelse bare at sende en command af gangen ... vender tilbage, men er ret sikker på at jeg har prøvet det og at det var dårlige performance. Derfor var jeg glad da jeg kunne se dette virkede godt :-)

Men ved at være så lang tid siden at det måske har været på en lidt anden måde ... can't remember ...

Vender tilbage når det er testet.

Skrevet lør. d. 17. januar 2009 kl. 22:58:41| #32

buzzzz
buzzzz (46.581 point)
ifyoudo.net
http://syska.dk/ (...)

Koden som er brugt er følgende ... gør jeg noget forkert her? Følgende update som du kan se i overstående ss, tager 1 min 35 sek, hvilket er ca. 19 gange langere end når jeg gør det med min MERGE ... :-s ...

Hvordan skal det lige laves for at kunne være så hurtig ? Jeg er helt tabt ...

StopWatch sw = new StopWatch();

            Regex reg = new Regex("(\\d+),(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+),'(.*)',(\\d+),'(.+)',(\\d+),'(.*)',(\\d+)", RegexOptions.Compiled);
            Match m;
            string s;
            List<WorldRow> list = new List<WorldRow>();
            WorldRow wr;
            int lines = 0;


            sw.Start();
            using (StreamReader sr = new StreamReader(@"C:\temp\DK\s4.travian.dk\2009-01-17.sql", Encoding.UTF8))
            {
                while (!sr.EndOfStream)
                {
                    lines++;

                    s = sr.ReadLine();
                    m = reg.Match(s);

                    if (reg.IsMatch(s))
                    {
                        wr = new WorldRow();

                        wr.CoorID = int.Parse(m.Groups[1].Value);
                        wr.X = short.Parse(m.Groups[2].Value);
                        wr.Y = short.Parse(m.Groups[3].Value);
                        wr.TID = byte.Parse(m.Groups[4].Value);
                        wr.VID = int.Parse(m.Groups[5].Value);
                        wr.VillageName = m.Groups[6].Value;
                        wr.UID = int.Parse(m.Groups[7].Value);
                        wr.PlayerName = m.Groups[8].Value;
                        wr.AID = (int.Parse(m.Groups[9].Value) == 0) ? null : (int?)int.Parse(m.Groups[9].Value);
                        wr.AllianceName = m.Groups[10].Value;
                        wr.Population = short.Parse(m.Groups[11].Value);

                        list.Add(wr);
                    }
                }
            }



            Console.WriteLine("Lines: {0}, Reg Hits: {1}", lines, list.Count);
            sw.Stop("Parse input");

            sw.Start();
            SqlConnection myConnection = new SqlConnection(connString);
            myConnection.Open();

            SqlCommand myCommand = myConnection.CreateCommand();
            SqlTransaction myTrans = null;

            myCommand.CommandText = "UPDATE Villages SET Population = @Population WHERE SID = @SID AND VID = @VID";
            SqlParameter pop = myCommand.Parameters.Add("@Population", System.Data.SqlDbType.SmallInt);
            SqlParameter sid = myCommand.Parameters.Add("@SID", System.Data.SqlDbType.SmallInt);
            SqlParameter vid = myCommand.Parameters.Add("@VID", System.Data.SqlDbType.Int);
            sid.Value = 7;
            try
            {
                for (int i = 0; i <= (list.Count / 1000); i++)
                {
                    // Start a local transaction
                    myTrans = myConnection.BeginTransaction();
                    // Must assign both transaction object and connection
                    // to Command object for a pending local transaction
                    // myCommand.Connection = myConnection;
                    myCommand.Transaction = myTrans;
                    foreach (WorldRow row in list.Skip(1000 * i).Take(1000))
                    {
                        pop.Value = row.Population;
                        vid.Value = row.VID;
                        myCommand.ExecuteNonQuery();
                    }
                    Console.WriteLine("First commit");
                    myTrans.Commit();   
                }
               
            }
            catch (Exception e)
            {
                try
                {
                    myTrans.Rollback();
                }
                catch (SqlException ex)
                {
                    if (myTrans.Connection != null)
                    {
                        Console.WriteLine("An exception of type " + ex.GetType() +
                                          " was encountered while attempting to roll back the transaction.");
                    }
                }

                Console.WriteLine("An exception of type " + e.GetType() +
                                  " was encountered while inserting the data.");
                Console.WriteLine("Neither record was written to database.");
            }
            finally
            {
                myConnection.Close();
            }
            sw.Stop("UPDATE");

Skrevet søn. d. 18. januar 2009 kl. 01:12:23| #33

arne_v
arne_v (1.005.658 point)
Hvis MEREGE er det hurtigste, så er det jo det.

Skrevet søn. d. 18. januar 2009 kl. 02:26:39| #34

buzzzz
buzzzz (46.581 point)
ifyoudo.net
ja ... men som sagt ... jeg kunne nemt have lavet noget galt ... også i overstående kode ... Databaser i den her størrelse er meget ny for mig ... så at noget kan gøres hurtigere på andre måder er sikkert ...

Normalt har jeg kun nogen få rows at updatere, men dette er jo i en helt anden størrelse.

// ouT

Skrevet søn. d. 18. januar 2009 kl. 04:29:48| #35

arne_v
arne_v (1.005.658 point)
Din TX kode er OK (jeg ville have nøjes med en neklet for løkke og commit når modulus 1000 var 0), men
det betyder næppe noget for total performance.

Jeg tror at konklusionen er at din merge er det bedste.

Jeg har ihvertfald ikke flere ideer.

Skrevet tor. d. 11. marts 2010 kl. 09:18:20| #36


Skrevet tor. d. 11. marts 2010 kl. 15:57:12| #37


Skrevet tor. d. 11. marts 2010 kl. 17:03:51| #38

buzzzz
buzzzz (46.581 point)
ifyoudo.net
og ham den anden ... web

Skriv et indlæg




Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] [img]link til billede[/img]
Web- og emailadresser omdannes automatisk til links

Log ind

   

   

Seneste spørgsmål

Koordinater for nyt vindue efter scroll, csharp.

Oprettet den 11. februar 2012 kl. 01.54
bjarnefilm giver 30 point for svar | Giv et svar »

Treeview hovedmenu á lá Dynamics C5

Oprettet den 10. februar 2012 kl. 08.12
olehaahr giver 30 point for svar | Giv et svar »

Deployment på Windows Mobile 6.5

Oprettet den 9. februar 2012 kl. 13.59
schristensen giver 200 point for svar | Giv et svar »

Seneste guides

Installer win 7
Den gode bruger


   




Tips & Tricks fra PC World

Teaser billede

Her er fem sjove danske websider du skal kende

Trænger dine lattermuskler til en omgang fitness på dansk? Vi viser vej til fem websider fyldt med humor og vanvittig satire.


Anmeldelser fra PC World

Teaser billede

Test: Denne super-tablet er iPads hårdeste konkurrent

Eee Pad Transformer Prime er frygtindgydende med sin quadcore processor og evne til at trylle sig om til bærbar. Apple bør kigge i bagspejlet, for Asus' tablet-pc kommer buldrende - og gør det...


Seneste blogindlæg

Teaser billede

Tvangslukke spørgsmål: Hvad er den bedste løsning?

Hej Vi har mange åbne spørgsmål på Eksperten. Vi ville gerne tvangslukke dem - så et spørgsmål efter f.eks. 6 måneder lukkes. Men der er et par uklarheder som ville være gode at få lidt input til:...


Nyheder fra PC World

Teaser billede

Nu kan du snart hente Windows 8

Den nye offentlige betaversion af Windows 8 er klar i denne måned.


Nyheder fra Computerworld

Teaser billede

Måske snart slut med Androids helt store problem

Android-platformen har længe været plaget af et særligt problem. Men måske er problemet nu ved at være elimineret.


Kurser
Samarbejdspartnere

Udgiver · © 2012 IDG Danmark A/S · Hørkær 18 · 2730 Herlev · Tlf.: 77 300 300 · Fax: 77 300 301 · Brug af personoplysninger